Commit 430cab6d authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] xattrr: preparation for fine-grained locking

From: Andreas Gruenbacher <agruen@suse.de>

Andrew Morton found that there is lock contention between extended
attribute operations (like reading ACLs, which `ls -l' needs to do)
and other operations on the same files. This is due to the fact that
all extended attribute syscalls take inode->i_sem before calling into
the filesystem code.

To fix this problem, this patch no longer takes inode->i_sem in the
getxattr and listxattr syscalls, and moves the lock taking code into
the file systems. (Another patch improves the locking strategy in
ext2 and ext3.)
parent a39afa31
...@@ -68,8 +68,8 @@ setattr: yes ...@@ -68,8 +68,8 @@ setattr: yes
permission: no permission: no
getattr: no getattr: no
setxattr: yes setxattr: yes
getxattr: yes getxattr: no
listxattr: yes listxattr: no
removexattr: yes removexattr: yes
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_sem on Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_sem on
victim. victim.
......
...@@ -204,11 +204,16 @@ ext2_getxattr(struct dentry *dentry, const char *name, ...@@ -204,11 +204,16 @@ ext2_getxattr(struct dentry *dentry, const char *name,
{ {
struct ext2_xattr_handler *handler; struct ext2_xattr_handler *handler;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
ssize_t error;
handler = ext2_xattr_resolve_name(&name); handler = ext2_xattr_resolve_name(&name);
if (!handler) if (!handler)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return handler->get(inode, name, buffer, size); down(&inode->i_sem);
error = handler->get(inode, name, buffer, size);
up(&inode->i_sem);
return error;
} }
/* /*
...@@ -219,7 +224,13 @@ ext2_getxattr(struct dentry *dentry, const char *name, ...@@ -219,7 +224,13 @@ ext2_getxattr(struct dentry *dentry, const char *name,
ssize_t ssize_t
ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) ext2_listxattr(struct dentry *dentry, char *buffer, size_t size)
{ {
return ext2_xattr_list(dentry->d_inode, buffer, size); ssize_t error;
down(&dentry->d_inode->i_sem);
error = ext2_xattr_list(dentry->d_inode, buffer, size);
up(&dentry->d_inode->i_sem);
return error;
} }
/* /*
......
...@@ -199,11 +199,16 @@ ext3_getxattr(struct dentry *dentry, const char *name, ...@@ -199,11 +199,16 @@ ext3_getxattr(struct dentry *dentry, const char *name,
{ {
struct ext3_xattr_handler *handler; struct ext3_xattr_handler *handler;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
ssize_t error;
handler = ext3_xattr_resolve_name(&name); handler = ext3_xattr_resolve_name(&name);
if (!handler) if (!handler)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return handler->get(inode, name, buffer, size); down(&inode->i_sem);
error = handler->get(inode, name, buffer, size);
up(&inode->i_sem);
return error;
} }
/* /*
...@@ -214,7 +219,13 @@ ext3_getxattr(struct dentry *dentry, const char *name, ...@@ -214,7 +219,13 @@ ext3_getxattr(struct dentry *dentry, const char *name,
ssize_t ssize_t
ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) ext3_listxattr(struct dentry *dentry, char *buffer, size_t size)
{ {
return ext3_xattr_list(dentry->d_inode, buffer, size); ssize_t error;
down(&dentry->d_inode->i_sem);
error = ext3_xattr_list(dentry->d_inode, buffer, size);
up(&dentry->d_inode->i_sem);
return error;
} }
/* /*
......
...@@ -964,10 +964,17 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, ...@@ -964,10 +964,17 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,
size_t buf_size) size_t buf_size)
{ {
return __jfs_getxattr(dentry->d_inode, name, data, buf_size); int err;
down(&dentry->d_inode->i_sem);
err = __jfs_getxattr(dentry->d_inode, name, data, buf_size);
up(&dentry->d_inode->i_sem);
return err;
} }
ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) static ssize_t __jfs_listxattr(struct dentry * dentry, char *data,
size_t buf_size)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
char *buffer; char *buffer;
...@@ -1013,6 +1020,17 @@ ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) ...@@ -1013,6 +1020,17 @@ ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
return size; return size;
} }
ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
{
int err;
down(&dentry->d_inode->i_sem);
err = __jfs_listxattr(dentry, data, buf_size);
up(&dentry->d_inode->i_sem);
return err;
}
int jfs_removexattr(struct dentry *dentry, const char *name) int jfs_removexattr(struct dentry *dentry, const char *name)
{ {
return __jfs_setxattr(dentry->d_inode, name, 0, 0, XATTR_REPLACE); return __jfs_setxattr(dentry->d_inode, name, 0, 0, XATTR_REPLACE);
......
...@@ -160,9 +160,7 @@ getxattr(struct dentry *d, char *name, void *value, size_t size) ...@@ -160,9 +160,7 @@ getxattr(struct dentry *d, char *name, void *value, size_t size)
error = security_inode_getxattr(d, kname); error = security_inode_getxattr(d, kname);
if (error) if (error)
goto out; goto out;
down(&d->d_inode->i_sem);
error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
up(&d->d_inode->i_sem);
} }
if (kvalue && error > 0) if (kvalue && error > 0)
...@@ -233,9 +231,7 @@ listxattr(struct dentry *d, char *list, size_t size) ...@@ -233,9 +231,7 @@ listxattr(struct dentry *d, char *list, size_t size)
error = security_inode_listxattr(d); error = security_inode_listxattr(d);
if (error) if (error)
goto out; goto out;
down(&d->d_inode->i_sem);
error = d->d_inode->i_op->listxattr(d, klist, size); error = d->d_inode->i_op->listxattr(d, klist, size);
up(&d->d_inode->i_sem);
} }
if (klist && error > 0) if (klist && error > 0)
......
...@@ -642,7 +642,7 @@ linvfs_setxattr( ...@@ -642,7 +642,7 @@ linvfs_setxattr(
} }
STATIC ssize_t STATIC ssize_t
linvfs_getxattr( __linvfs_getxattr(
struct dentry *dentry, struct dentry *dentry,
const char *name, const char *name,
void *data, void *data,
...@@ -697,9 +697,24 @@ linvfs_getxattr( ...@@ -697,9 +697,24 @@ linvfs_getxattr(
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
STATIC ssize_t
linvfs_getxattr(
struct dentry *dentry,
const char *name,
void *data,
size_t size)
{
int error;
down(&dentry->d_inode->i_sem);
error = __linvfs_getxattr(dentry, name, data, size);
up(&dentry->d_inode->i_sem);
return error;
}
STATIC ssize_t STATIC ssize_t
linvfs_listxattr( __linvfs_listxattr(
struct dentry *dentry, struct dentry *dentry,
char *data, char *data,
size_t size) size_t size)
...@@ -741,6 +756,21 @@ linvfs_listxattr( ...@@ -741,6 +756,21 @@ linvfs_listxattr(
return result; return result;
} }
STATIC ssize_t
linvfs_listxattr(
struct dentry *dentry,
char *data,
size_t size)
{
int error;
down(&dentry->d_inode->i_sem);
error = __linvfs_listxattr(dentry, data, size);
up(&dentry->d_inode->i_sem);
return error;
}
STATIC int STATIC int
linvfs_removexattr( linvfs_removexattr(
struct dentry *dentry, struct dentry *dentry,
......
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