From: Chris Mason <mason@suse.com>

From: jeffm@suse.com

reiserfs xattr locking fixes


---

 25-akpm/fs/reiserfs/inode.c            |    2 ++
 25-akpm/fs/reiserfs/xattr.c            |   32 ++++++++++++++++++++++++++------
 25-akpm/fs/reiserfs/xattr_acl.c        |   15 +++++++++++++--
 25-akpm/include/linux/reiserfs_fs_i.h  |    2 ++
 25-akpm/include/linux/reiserfs_xattr.h |   23 +++++++++++++++++++++++
 5 files changed, 66 insertions(+), 8 deletions(-)

diff -puN fs/reiserfs/inode.c~reiserfs-xattr-locking-02 fs/reiserfs/inode.c
--- 25/fs/reiserfs/inode.c~reiserfs-xattr-locking-02	Fri Apr 23 14:36:52 2004
+++ 25-akpm/fs/reiserfs/inode.c	Fri Apr 23 14:36:52 2004
@@ -979,6 +979,7 @@ static void init_inode (struct inode * i
     REISERFS_I(inode)->i_jl = NULL;
     REISERFS_I(inode)->i_acl_access = NULL;
     REISERFS_I(inode)->i_acl_default = NULL;
+    init_rwsem (&REISERFS_I(inode)->xattr_sem);
 
     if (stat_data_v1 (ih)) {
 	struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
@@ -1642,6 +1643,7 @@ int reiserfs_new_inode (struct reiserfs_
     sd_attrs_to_i_attrs( REISERFS_I(inode) -> i_attrs, inode );
     REISERFS_I(inode)->i_acl_access = NULL;
     REISERFS_I(inode)->i_acl_default = NULL;
+    init_rwsem (&REISERFS_I(inode)->xattr_sem);
 
     if (old_format_only (sb))
 	make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
diff -puN fs/reiserfs/xattr_acl.c~reiserfs-xattr-locking-02 fs/reiserfs/xattr_acl.c
--- 25/fs/reiserfs/xattr_acl.c~reiserfs-xattr-locking-02	Fri Apr 23 14:36:52 2004
+++ 25-akpm/fs/reiserfs/xattr_acl.c	Fri Apr 23 14:36:52 2004
@@ -399,9 +399,11 @@ reiserfs_cache_default_acl (struct inode
     if (reiserfs_posixacl (inode->i_sb) &&
         !is_reiserfs_priv_object (inode)) {
         struct posix_acl *acl;
+        reiserfs_read_lock_xattr_i (inode);
         reiserfs_read_lock_xattrs (inode->i_sb);
         acl = reiserfs_get_acl (inode, ACL_TYPE_DEFAULT);
         reiserfs_read_unlock_xattrs (inode->i_sb);
+        reiserfs_read_unlock_xattr_i (inode);
         ret = acl ? 1 : 0;
         posix_acl_release (acl);
     }
@@ -437,9 +439,18 @@ reiserfs_acl_chmod (struct inode *inode)
                 return -ENOMEM;
         error = posix_acl_chmod_masq(clone, inode->i_mode);
         if (!error) {
-                reiserfs_write_lock_xattrs (inode->i_sb);
+                int lock = !has_xattr_dir (inode);
+                reiserfs_write_lock_xattr_i (inode);
+                if (lock)
+                    reiserfs_write_lock_xattrs (inode->i_sb);
+                else
+                    reiserfs_read_lock_xattrs (inode->i_sb);
                 error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
-                reiserfs_write_unlock_xattrs (inode->i_sb);
+                if (lock)
+                    reiserfs_write_unlock_xattrs (inode->i_sb);
+                else
+                    reiserfs_read_unlock_xattrs (inode->i_sb);
+                reiserfs_write_unlock_xattr_i (inode);
         }
         posix_acl_release(clone);
         return error;
diff -puN fs/reiserfs/xattr.c~reiserfs-xattr-locking-02 fs/reiserfs/xattr.c
--- 25/fs/reiserfs/xattr.c~reiserfs-xattr-locking-02	Fri Apr 23 14:36:52 2004
+++ 25-akpm/fs/reiserfs/xattr.c	Fri Apr 23 14:36:52 2004
@@ -521,6 +521,7 @@ open_file:
     }
 
     xinode = fp->f_dentry->d_inode;
+    REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
 
     /* we need to copy it off.. */
     if (xinode->i_nlink > 1) {
@@ -631,6 +632,7 @@ reiserfs_xattr_get (const struct inode *
 
     xinode = fp->f_dentry->d_inode;
     isize = xinode->i_size;
+    REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
 
     /* Just return the size needed */
     if (buffer == NULL) {
@@ -834,6 +836,8 @@ out_dir:
     fput(fp);
 
 out:
+    if (!err)
+        REISERFS_I(inode)->i_flags = REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
     return err;
 }
 
@@ -945,11 +949,11 @@ reiserfs_getxattr (struct dentry *dentry
         get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
         return -EOPNOTSUPP;
 
-    down (&dentry->d_inode->i_sem);
+    reiserfs_read_lock_xattr_i (dentry->d_inode);
     reiserfs_read_lock_xattrs (dentry->d_sb);
     err = xah->get (dentry->d_inode, name, buffer, size);
     reiserfs_read_unlock_xattrs (dentry->d_sb);
-    up (&dentry->d_inode->i_sem);
+    reiserfs_read_unlock_xattr_i (dentry->d_inode);
     return err;
 }
 
@@ -965,6 +969,7 @@ reiserfs_setxattr (struct dentry *dentry
 {
     struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
     int err;
+    int lock;
 
     if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
         get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
@@ -976,9 +981,18 @@ reiserfs_setxattr (struct dentry *dentry
     if (IS_IMMUTABLE (dentry->d_inode) || IS_APPEND (dentry->d_inode))
         return -EROFS;
 
-    reiserfs_write_lock_xattrs (dentry->d_sb);
+    reiserfs_write_lock_xattr_i (dentry->d_inode);
+    lock = !has_xattr_dir (dentry->d_inode);
+    if (lock)
+        reiserfs_write_lock_xattrs (dentry->d_sb);
+    else
+        reiserfs_read_lock_xattrs (dentry->d_sb);
     err = xah->set (dentry->d_inode, name, value, size, flags);
-    reiserfs_write_unlock_xattrs (dentry->d_sb);
+    if (lock)
+        reiserfs_write_unlock_xattrs (dentry->d_sb);
+    else
+        reiserfs_read_unlock_xattrs (dentry->d_sb);
+    reiserfs_write_unlock_xattr_i (dentry->d_inode);
     return err;
 }
 
@@ -1003,6 +1017,7 @@ reiserfs_removexattr (struct dentry *den
     if (IS_IMMUTABLE (dentry->d_inode) || IS_APPEND (dentry->d_inode))
         return -EPERM;
 
+    reiserfs_write_lock_xattr_i (dentry->d_inode);
     reiserfs_read_lock_xattrs (dentry->d_sb);
 
     /* Deletion pre-operation */
@@ -1019,6 +1034,7 @@ reiserfs_removexattr (struct dentry *den
 
 out:
     reiserfs_read_unlock_xattrs (dentry->d_sb);
+    reiserfs_write_unlock_xattr_i (dentry->d_inode);
     return err;
 }
 
@@ -1081,7 +1097,7 @@ reiserfs_listxattr (struct dentry *dentr
         get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
         return -EOPNOTSUPP;
 
-    down (&dentry->d_inode->i_sem);
+    reiserfs_read_lock_xattr_i (dentry->d_inode);
     reiserfs_read_lock_xattrs (dentry->d_sb);
     dir = open_xa_dir (dentry->d_inode, FL_READONLY);
     reiserfs_read_unlock_xattrs (dentry->d_sb);
@@ -1104,6 +1120,8 @@ reiserfs_listxattr (struct dentry *dentr
     buf.r_pos = 0;
     buf.r_inode = dentry->d_inode;
 
+    REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir;
+
     err = xattr_readdir (fp, reiserfs_listxattr_filler, &buf);
     if (err)
         goto out_dir;
@@ -1117,7 +1135,7 @@ out_dir:
     fput(fp);
 
 out:
-    up (&dentry->d_inode->i_sem);
+    reiserfs_read_unlock_xattr_i (dentry->d_inode);
     return err;
 }
 
@@ -1352,11 +1370,13 @@ __reiserfs_permission (struct inode *ino
 		if (!(mode & S_IRWXG))
 			goto check_groups;
 
+                reiserfs_read_lock_xattr_i (inode);
                 if (need_lock)
                     reiserfs_read_lock_xattrs (inode->i_sb);
                 acl = reiserfs_get_acl (inode, ACL_TYPE_ACCESS);
                 if (need_lock)
                     reiserfs_read_unlock_xattrs (inode->i_sb);
+                reiserfs_read_unlock_xattr_i (inode);
                 if (IS_ERR (acl)) {
                     if (PTR_ERR (acl) == -ENODATA)
                         goto check_groups;
diff -puN include/linux/reiserfs_fs_i.h~reiserfs-xattr-locking-02 include/linux/reiserfs_fs_i.h
--- 25/include/linux/reiserfs_fs_i.h~reiserfs-xattr-locking-02	Fri Apr 23 14:36:52 2004
+++ 25-akpm/include/linux/reiserfs_fs_i.h	Fri Apr 23 14:36:52 2004
@@ -24,6 +24,7 @@ typedef enum {
     i_link_saved_unlink_mask   =  0x0010,
     i_link_saved_truncate_mask =  0x0020,
     i_priv_object              =  0x0080,
+    i_has_xattr_dir            =  0x0100,
 } reiserfs_inode_flags;
 
 
@@ -55,6 +56,7 @@ struct reiserfs_inode_info {
 
     struct posix_acl *i_acl_access;
     struct posix_acl *i_acl_default;
+    struct rw_semaphore xattr_sem;
     struct inode vfs_inode;
 };
 
diff -puN include/linux/reiserfs_xattr.h~reiserfs-xattr-locking-02 include/linux/reiserfs_xattr.h
--- 25/include/linux/reiserfs_xattr.h~reiserfs-xattr-locking-02	Fri Apr 23 14:36:52 2004
+++ 25-akpm/include/linux/reiserfs_xattr.h	Fri Apr 23 14:36:52 2004
@@ -32,6 +32,7 @@ struct reiserfs_xattr_handler {
 
 #ifdef CONFIG_REISERFS_FS_XATTR
 #define is_reiserfs_priv_object(inode) (REISERFS_I(inode)->i_flags & i_priv_object)
+#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
 ssize_t reiserfs_getxattr (struct dentry *dentry, const char *name,
 			   void *buffer, size_t size);
 int reiserfs_setxattr (struct dentry *dentry, const char *name,
@@ -80,6 +81,28 @@ reiserfs_read_unlock_xattrs(struct super
     up_read (&REISERFS_XATTR_DIR_SEM(sb));
 }
 
+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);
+}
+
 #else
 
 #define is_reiserfs_priv_object(inode) 0

_