aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2006-10-17 13:50:36 -0400
committerJens Axboe <axboe@nelson.home.kernel.dk>2006-10-19 14:53:08 -0400
commit01de85e057328ecbef36e108673b1e81059d54c1 (patch)
tree0dbac62e48b2a2fa3f4ec4dea9b340ff31892a8c
parent6da61809822c22634a3de2dcb3c60283b836a88a (diff)
[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>
-rw-r--r--include/linux/fs.h2
-rw-r--r--mm/filemap.c30
2 files changed, 24 insertions, 8 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d695ba2346a3..2fe6e3f900ba 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1712,6 +1712,8 @@ extern void __iget(struct inode * inode);
1712extern void clear_inode(struct inode *); 1712extern void clear_inode(struct inode *);
1713extern void destroy_inode(struct inode *); 1713extern void destroy_inode(struct inode *);
1714extern struct inode *new_inode(struct super_block *); 1714extern struct inode *new_inode(struct super_block *);
1715extern int __remove_suid(struct dentry *, int);
1716extern int should_remove_suid(struct dentry *);
1715extern int remove_suid(struct dentry *); 1717extern int remove_suid(struct dentry *);
1716extern void remove_dquot_ref(struct super_block *, int, struct list_head *); 1718extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
1717 1719
diff --git a/mm/filemap.c b/mm/filemap.c
index 3464b681f844..7c7addb9333c 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1884,11 +1884,10 @@ repeat:
1884 * if suid or (sgid and xgrp) 1884 * if suid or (sgid and xgrp)
1885 * remove privs 1885 * remove privs
1886 */ 1886 */
1887int remove_suid(struct dentry *dentry) 1887int should_remove_suid(struct dentry *dentry)
1888{ 1888{
1889 mode_t mode = dentry->d_inode->i_mode; 1889 mode_t mode = dentry->d_inode->i_mode;
1890 int kill = 0; 1890 int kill = 0;
1891 int result = 0;
1892 1891
1893 /* suid always must be killed */ 1892 /* suid always must be killed */
1894 if (unlikely(mode & S_ISUID)) 1893 if (unlikely(mode & S_ISUID))
@@ -1901,13 +1900,28 @@ int remove_suid(struct dentry *dentry)
1901 if (unlikely((mode & S_ISGID) && (mode & S_IXGRP))) 1900 if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
1902 kill |= ATTR_KILL_SGID; 1901 kill |= ATTR_KILL_SGID;
1903 1902
1904 if (unlikely(kill && !capable(CAP_FSETID))) { 1903 if (unlikely(kill && !capable(CAP_FSETID)))
1905 struct iattr newattrs; 1904 return kill;
1906 1905
1907 newattrs.ia_valid = ATTR_FORCE | kill; 1906 return 0;
1908 result = notify_change(dentry, &newattrs); 1907}
1909 } 1908
1910 return result; 1909int __remove_suid(struct dentry *dentry, int kill)
1910{
1911 struct iattr newattrs;
1912
1913 newattrs.ia_valid = ATTR_FORCE | kill;
1914 return notify_change(dentry, &newattrs);
1915}
1916
1917int remove_suid(struct dentry *dentry)
1918{
1919 int kill = should_remove_suid(dentry);
1920
1921 if (unlikely(kill))
1922 return __remove_suid(dentry, kill);
1923
1924 return 0;
1911} 1925}
1912EXPORT_SYMBOL(remove_suid); 1926EXPORT_SYMBOL(remove_suid);
1913 1927