[PATCH] Add lockless helpers for remove_suid()
Right now users have to grab i_mutex before calling remove_suid(), in the unlikely event that a call to ->setattr() may be needed. Split up the function in two parts: - One to check if we need to remove suid - One to actually remove it The first we can call lockless. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
parent
6da6180982
commit
01de85e057
2 changed files with 24 additions and 8 deletions
|
@ -1712,6 +1712,8 @@ extern void __iget(struct inode * inode);
|
|||
extern void clear_inode(struct inode *);
|
||||
extern void destroy_inode(struct inode *);
|
||||
extern struct inode *new_inode(struct super_block *);
|
||||
extern int __remove_suid(struct dentry *, int);
|
||||
extern int should_remove_suid(struct dentry *);
|
||||
extern int remove_suid(struct dentry *);
|
||||
extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
|
||||
|
||||
|
|
30
mm/filemap.c
30
mm/filemap.c
|
@ -1884,11 +1884,10 @@ __grab_cache_page(struct address_space *mapping, unsigned long index,
|
|||
* if suid or (sgid and xgrp)
|
||||
* remove privs
|
||||
*/
|
||||
int remove_suid(struct dentry *dentry)
|
||||
int should_remove_suid(struct dentry *dentry)
|
||||
{
|
||||
mode_t mode = dentry->d_inode->i_mode;
|
||||
int kill = 0;
|
||||
int result = 0;
|
||||
|
||||
/* suid always must be killed */
|
||||
if (unlikely(mode & S_ISUID))
|
||||
|
@ -1901,13 +1900,28 @@ int remove_suid(struct dentry *dentry)
|
|||
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
|
||||
kill |= ATTR_KILL_SGID;
|
||||
|
||||
if (unlikely(kill && !capable(CAP_FSETID))) {
|
||||
struct iattr newattrs;
|
||||
if (unlikely(kill && !capable(CAP_FSETID)))
|
||||
return kill;
|
||||
|
||||
newattrs.ia_valid = ATTR_FORCE | kill;
|
||||
result = notify_change(dentry, &newattrs);
|
||||
}
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __remove_suid(struct dentry *dentry, int kill)
|
||||
{
|
||||
struct iattr newattrs;
|
||||
|
||||
newattrs.ia_valid = ATTR_FORCE | kill;
|
||||
return notify_change(dentry, &newattrs);
|
||||
}
|
||||
|
||||
int remove_suid(struct dentry *dentry)
|
||||
{
|
||||
int kill = should_remove_suid(dentry);
|
||||
|
||||
if (unlikely(kill))
|
||||
return __remove_suid(dentry, kill);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(remove_suid);
|
||||
|
||||
|
|
Loading…
Reference in a new issue