Commit 30304fc9 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] reiserfs: xattr locking fixes

From: Chris Mason <mason@suse.com>

From: jeffm@suse.com

reiserfs xattr locking fixes
parent 647c60b9
......@@ -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);
......
......@@ -521,6 +521,7 @@ reiserfs_xattr_set (struct inode *inode, const char *name, const void *buffer,
}
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 @@ reiserfs_delete_xattrs (struct inode *inode)
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_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);
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 @@ reiserfs_listxattr (struct dentry *dentry, char *buffer, size_t size)
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;
......
......@@ -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) {
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);
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;
......
......@@ -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;
};
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment