From: viro@parcelfarce.linux.theplanet.co.uk bernhard_heibler@gmx.de has discovered that NFS is very slow when writing to a file which has execute permissions. See http://bugme.osdl.org/show_bug.cgi?id=1936 This patch fixes remove_suid() to not try to modify the inode mode on every write to such a file. --- 25-akpm/mm/filemap.c | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-) diff -puN mm/filemap.c~remove_suid-fix mm/filemap.c --- 25/mm/filemap.c~remove_suid-fix Thu Jan 22 16:11:18 2004 +++ 25-akpm/mm/filemap.c Thu Jan 22 16:11:18 2004 @@ -1495,22 +1495,32 @@ repeat: return page; } +/* + * The logic we want is + * + * if suid or (sgid and xgrp) + * remove privs + */ void remove_suid(struct dentry *dentry) { struct iattr newattrs; - struct inode *inode = dentry->d_inode; - unsigned int mode = inode->i_mode & (S_ISUID|S_ISGID|S_IXGRP); - - if (!(mode & S_IXGRP)) - mode &= S_ISUID; + mode_t mode = dentry->d_inode->i_mode; - /* were any of the uid bits set? */ - if (mode && !capable(CAP_FSETID)) { - newattrs.ia_valid = ATTR_KILL_SUID|ATTR_KILL_SGID|ATTR_FORCE; - notify_change(dentry, &newattrs); + if (likely(!(mode & S_ISUID))) { + /* common case - neither suid nor sgid */ + if (likely(!(mode & S_ISGID))) + return; + /* if it's not group-executable, leave sgid alone */ + if (!(mode & S_IXGRP)) + return; } + /* we have suid or real sgid; are we allowed to keep them? */ + if (capable(CAP_FSETID)) + return; + /* OK, remove SUID */ + newattrs.ia_valid = ATTR_KILL_SUID|ATTR_KILL_SGID|ATTR_FORCE; + notify_change(dentry, &newattrs); } - EXPORT_SYMBOL(remove_suid); /* _