[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 clear_inode(struct inode *);
|
||||||
extern void destroy_inode(struct inode *);
|
extern void destroy_inode(struct inode *);
|
||||||
extern struct inode *new_inode(struct super_block *);
|
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 int remove_suid(struct dentry *);
|
||||||
extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
|
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)
|
* if suid or (sgid and xgrp)
|
||||||
* remove privs
|
* remove privs
|
||||||
*/
|
*/
|
||||||
int remove_suid(struct dentry *dentry)
|
int should_remove_suid(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
mode_t mode = dentry->d_inode->i_mode;
|
mode_t mode = dentry->d_inode->i_mode;
|
||||||
int kill = 0;
|
int kill = 0;
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
/* suid always must be killed */
|
/* suid always must be killed */
|
||||||
if (unlikely(mode & S_ISUID))
|
if (unlikely(mode & S_ISUID))
|
||||||
|
@ -1901,13 +1900,28 @@ int remove_suid(struct dentry *dentry)
|
||||||
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
|
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
|
||||||
kill |= ATTR_KILL_SGID;
|
kill |= ATTR_KILL_SGID;
|
||||||
|
|
||||||
if (unlikely(kill && !capable(CAP_FSETID))) {
|
if (unlikely(kill && !capable(CAP_FSETID)))
|
||||||
struct iattr newattrs;
|
return kill;
|
||||||
|
|
||||||
newattrs.ia_valid = ATTR_FORCE | kill;
|
return 0;
|
||||||
result = notify_change(dentry, &newattrs);
|
}
|
||||||
}
|
|
||||||
return result;
|
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);
|
EXPORT_SYMBOL(remove_suid);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue