From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH 13/39] reiserfs: make per-inode xattr locking more fine grained

 The per-inode locking can be made more fine-grained to surround just the
 interaction with the filesystem itself. This really only applies to protecting
 reads during a write, since concurrent writes are barred with inode->i_mutex
 at the vfs level.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

--
 fs/reiserfs/inode.c            |    2 -
 fs/reiserfs/xattr.c            |   62 +++++++++++++++++------------------------
 fs/reiserfs/xattr_acl.c        |    7 ----
 include/linux/reiserfs_fs_i.h  |    3 -
 include/linux/reiserfs_xattr.h |   26 -----------------
 5 files changed, 28 insertions(+), 72 deletions(-)

--- a/fs/reiserfs/inode.c	2007-06-11 14:49:36.000000000 -0400
+++ b/fs/reiserfs/inode.c	2007-06-11 14:50:06.000000000 -0400
@@ -1128,7 +1128,6 @@ static void init_inode(struct inode *ino
 	mutex_init(&(REISERFS_I(inode)->i_mmap));
 	reiserfs_init_acl_access(inode);
 	reiserfs_init_acl_default(inode);
-	reiserfs_init_xattr_rwsem(inode);
 
 	if (stat_data_v1(ih)) {
 		struct stat_data_v1 *sd =
@@ -1832,7 +1831,6 @@ int reiserfs_new_inode(struct reiserfs_t
 	mutex_init(&(REISERFS_I(inode)->i_mmap));
 	reiserfs_init_acl_access(inode);
 	reiserfs_init_acl_default(inode);
-	reiserfs_init_xattr_rwsem(inode);
 
 	if (old_format_only(sb))
 		make_le_item_head(&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET,
--- a/fs/reiserfs/xattr.c	2007-06-11 14:49:36.000000000 -0400
+++ b/fs/reiserfs/xattr.c	2007-06-11 14:50:07.000000000 -0400
@@ -29,10 +29,8 @@
  * to the inode so that unnecessary lookups are avoided.
  *
  * Locking works like so:
- * The xattr root (/.reiserfs_priv/xattrs) is protected by its i_mutex.
- * The xattr dir (/.reiserfs_priv/xattrs/<oid>.<gen>) is protected by
- * inode->xattr_sem.
- * The xattrs themselves are likewise protected by the xattr_sem.
+ * Every component (xattr root, xattr dir, and the xattrs themselves) are
+ * protected by their i_mutex.
  */
 
 #include <linux/reiserfs_fs.h>
@@ -318,16 +316,12 @@ int xattr_readdir(struct file *file, fil
 	int res = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
 		goto out;
-	mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
-//        down(&inode->i_zombie);
 	res = -ENOENT;
 	if (!IS_DEADDIR(inode)) {
 		lock_kernel();
 		res = __xattr_readdir(file, buf, filler);
 		unlock_kernel();
 	}
-//        up(&inode->i_zombie);
-	mutex_unlock(&inode->i_mutex);
       out:
 	return res;
 }
@@ -387,9 +381,8 @@ reiserfs_xattr_set(struct inode *inode, 
 	if (get_inode_sd_version(inode) == STAT_DATA_V1)
 		return -EOPNOTSUPP;
 
-	/* Empty xattrs are ok, they're just empty files, no hash */
-	if (buffer && buffer_size)
-		xahash = xattr_hash(buffer, buffer_size);
+	if (!buffer)
+		return reiserfs_xattr_del(inode, name);
 
       open_file:
 	fp = open_xattr_file(inode, name, flags);
@@ -398,6 +391,7 @@ reiserfs_xattr_set(struct inode *inode, 
 		goto out;
 	}
 
+	xahash = xattr_hash(buffer, buffer_size);
 	xinode = fp->f_path.dentry->d_inode;
 	REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
 
@@ -531,6 +525,8 @@ reiserfs_xattr_get(const struct inode *i
 		goto out_fput;
 	}
 
+	mutex_lock(&fp->f_path.dentry->d_inode->i_mutex);
+
 	while (file_pos < isize) {
 		size_t chunk;
 		char *data;
@@ -585,6 +581,7 @@ reiserfs_xattr_get(const struct inode *i
 	}
 
       out_fput:
+	mutex_unlock(&fp->f_path.dentry->d_inode->i_mutex);
 	fput(fp);
 
       out:
@@ -597,6 +594,7 @@ __reiserfs_xattr_del(struct dentry *xadi
 	struct dentry *dentry;
 	struct inode *dir = xadir->d_inode;
 	int err = 0;
+	struct reiserfs_xattr_handler *xah;
 
 	dentry = lookup_one_len(name, xadir, namelen);
 	if (IS_ERR(dentry)) {
@@ -624,6 +622,14 @@ __reiserfs_xattr_del(struct dentry *xadi
 		return -EIO;
 	}
 
+	/* Deletion pre-operation */
+	xah = find_xattr_handler_prefix(name);
+	if (xah && xah->del) {
+		err = xah->del(inode, name);
+		if (err)
+			goto out;
+	}
+
 	err = vfs_unlink(xadir->d_inode, dentry);
 
       out_file:
@@ -644,7 +650,9 @@ int reiserfs_xattr_del(struct inode *ino
 		goto out;
 	}
 
+	mutex_lock(&dir->i_mutex);
 	err = __reiserfs_xattr_del(dir, name, strlen(name));
+	mutex_unlock(&dir->i_mutex);
 	dput(dir);
 
 	if (!err) {
@@ -689,7 +697,8 @@ int reiserfs_delete_xattrs(struct inode 
 		goto out;
 	} else if (!dir->d_inode) {
 		dput(dir);
-		return 0;
+		err = 0;
+		goto out;
 	}
 
 	fp = dentry_open(dir, NULL, O_RDWR);
@@ -699,12 +708,13 @@ int reiserfs_delete_xattrs(struct inode 
 		goto out;
 	}
 
+	mutex_lock_nested(&fp->f_path.dentry->d_inode->i_mutex, I_MUTEX_XATTR);
 	lock_kernel();
 	err = xattr_readdir(fp, reiserfs_delete_xattrs_filler, dir);
-	if (err) {
-		unlock_kernel();
+	unlock_kernel();
+	mutex_unlock(&fp->f_path.dentry->d_inode->i_mutex);
+	if (err)
 		goto out_dir;
-	}
 
 	/* Leftovers besides . and .. -- that's not good. */
 	if (dir->d_inode->i_nlink <= 2) {
@@ -717,7 +727,6 @@ int reiserfs_delete_xattrs(struct inode 
 		reiserfs_warning(inode->i_sb, "jdm-20004",
 				 "Couldn't remove all entries in directory");
 	}
-	unlock_kernel();
 
       out_dir:
 	fput(fp);
@@ -791,6 +800,7 @@ int reiserfs_chown_xattrs(struct inode *
 		goto out;
 	}
 
+	mutex_lock_nested(&fp->f_path.dentry->d_inode->i_mutex, I_MUTEX_XATTR);
 	lock_kernel();
 
 	attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
@@ -808,6 +818,7 @@ int reiserfs_chown_xattrs(struct inode *
 	unlock_kernel();
 
       out_dir:
+	mutex_unlock(&fp->f_path.dentry->d_inode->i_mutex);
 	fput(fp);
 
       out:
@@ -831,9 +842,7 @@ reiserfs_getxattr(struct dentry * dentry
 	    get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
 		return -EOPNOTSUPP;
 
-	reiserfs_read_lock_xattr_i(dentry->d_inode);
 	err = xah->get(dentry->d_inode, name, buffer, size);
-	reiserfs_read_unlock_xattr_i(dentry->d_inode);
 	return err;
 }
 
@@ -853,9 +862,7 @@ reiserfs_setxattr(struct dentry *dentry,
 	    get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
 		return -EOPNOTSUPP;
 
-	reiserfs_write_lock_xattr_i(dentry->d_inode);
 	err = xah->set(dentry->d_inode, name, value, size, flags);
-	reiserfs_write_unlock_xattr_i(dentry->d_inode);
 	return err;
 }
 
@@ -873,21 +880,12 @@ int reiserfs_removexattr(struct dentry *
 	    get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
 		return -EOPNOTSUPP;
 
-	reiserfs_write_lock_xattr_i(dentry->d_inode);
-	/* Deletion pre-operation */
-	if (xah->del) {
-		err = xah->del(dentry->d_inode, name);
-		if (err)
-			goto out;
-	}
-
 	err = reiserfs_xattr_del(dentry->d_inode, name);
 
 	dentry->d_inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(dentry->d_inode);
 
       out:
-	reiserfs_write_unlock_xattr_i(dentry->d_inode);
 	return err;
 }
 
@@ -950,7 +948,6 @@ ssize_t reiserfs_listxattr(struct dentry
 	    get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
 		return -EOPNOTSUPP;
 
-	reiserfs_read_lock_xattr_i(dentry->d_inode);
 	dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE);
 	if (IS_ERR(dir)) {
 		err = PTR_ERR(dir);
@@ -986,7 +983,6 @@ ssize_t reiserfs_listxattr(struct dentry
 	fput(fp);
 
       out:
-	reiserfs_read_unlock_xattr_i(dentry->d_inode);
 	return err;
 }
 
@@ -1190,12 +1186,8 @@ static int reiserfs_check_acl(struct ino
 	struct posix_acl *acl;
 	int error = -EAGAIN; /* do regular unix permission checks by default */
 
-	reiserfs_read_lock_xattr_i(inode);
-
 	acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
 
-	reiserfs_read_unlock_xattr_i(inode);
-
 	if (acl) {
 		if (!IS_ERR(acl)) {
 			error = posix_acl_permission(inode, acl, mask);
--- a/fs/reiserfs/xattr_acl.c	2007-06-11 14:49:36.000000000 -0400
+++ b/fs/reiserfs/xattr_acl.c	2007-06-11 14:50:06.000000000 -0400
@@ -418,9 +418,7 @@ int reiserfs_cache_default_acl(struct in
 	int ret = 0;
 	if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) {
 		struct posix_acl *acl;
-		reiserfs_read_lock_xattr_i(inode);
 		acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
-		reiserfs_read_unlock_xattr_i(inode);
 		ret = (acl && !IS_ERR(acl));
 		if (ret)
 			posix_acl_release(acl);
@@ -452,11 +450,8 @@ int reiserfs_acl_chmod(struct inode *ino
 	if (!clone)
 		return -ENOMEM;
 	error = posix_acl_chmod_masq(clone, inode->i_mode);
-	if (!error) {
-		reiserfs_write_lock_xattr_i(inode);
+	if (!error)
 		error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
-		reiserfs_write_unlock_xattr_i(inode);
-	}
 	posix_acl_release(clone);
 	return error;
 }
--- a/include/linux/reiserfs_fs_i.h	2007-06-11 14:49:05.000000000 -0400
+++ b/include/linux/reiserfs_fs_i.h	2007-06-11 14:50:06.000000000 -0400
@@ -58,9 +58,6 @@ struct reiserfs_inode_info {
 	struct posix_acl *i_acl_access;
 	struct posix_acl *i_acl_default;
 #endif
-#ifdef CONFIG_REISERFS_FS_XATTR
-	struct rw_semaphore xattr_sem;
-#endif
 	struct inode vfs_inode;
 };
 
--- a/include/linux/reiserfs_xattr.h	2007-06-11 14:49:36.000000000 -0400
+++ b/include/linux/reiserfs_xattr.h	2007-06-11 14:50:06.000000000 -0400
@@ -68,34 +68,12 @@ extern struct reiserfs_xattr_handler sec
 int reiserfs_xattr_register_handlers(void) __init;
 void reiserfs_xattr_unregister_handlers(void);
 
-static inline void reiserfs_write_lock_xattr_i(struct inode *inode)
-{
-	down_write(&REISERFS_I(inode)->xattr_sem);
-}
-static inline void reiserfs_write_unlock_xattr_i(struct inode *inode)
-{
-	up_write(&REISERFS_I(inode)->xattr_sem);
-}
-static inline void reiserfs_read_lock_xattr_i(struct inode *inode)
-{
-	down_read(&REISERFS_I(inode)->xattr_sem);
-}
-
-static inline void reiserfs_read_unlock_xattr_i(struct inode *inode)
-{
-	up_read(&REISERFS_I(inode)->xattr_sem);
-}
 
 static inline void reiserfs_mark_inode_private(struct inode *inode)
 {
 	inode->i_flags |= S_PRIVATE;
 }
 
-static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
-{
-	init_rwsem(&REISERFS_I(inode)->xattr_sem);
-}
-
 #else
 
 #define is_reiserfs_priv_object(inode) 0
@@ -104,10 +82,6 @@ static inline void reiserfs_init_xattr_r
 #define reiserfs_setxattr NULL
 #define reiserfs_listxattr NULL
 #define reiserfs_removexattr NULL
-#define reiserfs_write_lock_xattrs(sb) do {;} while(0)
-#define reiserfs_write_unlock_xattrs(sb) do {;} while(0)
-#define reiserfs_read_lock_xattrs(sb)
-#define reiserfs_read_unlock_xattrs(sb)
 
 #define reiserfs_permission NULL
 
