]> git.hungrycats.org Git - linux/commitdiff
[PATCH] reiserfs: xattr locking fixes
authorAndrew Morton <akpm@osdl.org>
Mon, 10 May 2004 06:59:58 +0000 (23:59 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 10 May 2004 06:59:58 +0000 (23:59 -0700)
From: Chris Mason <mason@suse.com>

From: jeffm@suse.com

reiserfs xattr locking fixes

fs/reiserfs/inode.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr_acl.c
include/linux/reiserfs_fs_i.h
include/linux/reiserfs_xattr.h

index 593f543db21c0982e10e090946143bf0227f1204..d1a34737c6a2ecde98e9b5b49784c6ab91b7df31 100644 (file)
@@ -979,6 +979,7 @@ static void init_inode (struct inode * inode, struct path * path)
     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_transaction_handle *th,
     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);
index 0c4e2d617d914357c93b6e1d758d005a30920363..924d895402b8431fdc45bc0ba51987a87b4edd0e 100644 (file)
@@ -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 *inode, const char *name, void *buffer,
 
     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, const char *name, void *buffer,
         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, const char *name, const void *value,
 {
     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, const char *name, const void *value,
     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 *dentry, const char *name)
     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 *dentry, const char *name)
 
 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 *dentry, char *buffer, size_t size)
         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 *dentry, char *buffer, size_t size)
     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 *inode, int mask, struct nameidata *nd,
                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;
index cded5426c3daae4bd59e9b5f6a7d751bb622ccf1..623139f062d3fe51ab5d131d0b75d88335f384c2 100644 (file)
@@ -399,9 +399,11 @@ reiserfs_cache_default_acl (struct inode *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;
index 67bc69db28b467d35168488edce631d34b5db44e..57eeaf7ed6bd1fb4017301ce6b9f61d11c15e3c6 100644 (file)
@@ -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;
 };
 
index 3f4480b8a2cdd8ebc74c74b7c93b83fd4b01d93e..9c40c4e9ba03531ddd22a7f22ea675f9647eb744 100644 (file)
@@ -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_block *sb)
     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