From: Chris Mason 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 _