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);
 
 /*

_