* [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len
@ 2009-05-01 16:11 Jeff Mahoney
2009-05-01 16:37 ` Alexander Beregalov
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Jeff Mahoney @ 2009-05-01 16:11 UTC (permalink / raw)
To: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton,
Al Viro, Alexander Beregalov, David
2.6.30-rc3 introduced some sanity checks in the VFS code to avoid NFS
bugs by ensuring that lookup_one_len is always called under i_mutex.
This patch expands the i_mutex locking to enclose lookup_one_len. This was
always required, but not not enforced in the reiserfs code since it
does locking around the xattr interactions with the xattr_sem.
This is obvious enough, but it survived an overnight 50 thread ACL test.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
fs/reiserfs/xattr.c | 32 ++++++++++++++------------------
1 file changed, 14 insertions(+), 18 deletions(-)
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -120,25 +120,20 @@ static struct dentry *lookup_or_create_d
struct dentry *dentry;
BUG_ON(!parent);
+ mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_XATTR);
dentry = lookup_one_len(name, parent, strlen(name));
- if (IS_ERR(dentry))
- return dentry;
- else if (!dentry->d_inode) {
+ if (!IS_ERR(dentry) && !dentry->d_inode) {
int err = -ENODATA;
- if (xattr_may_create(flags)) {
- mutex_lock_nested(&parent->d_inode->i_mutex,
- I_MUTEX_XATTR);
+ if (xattr_may_create(flags))
err = xattr_mkdir(parent->d_inode, dentry, 0700);
- mutex_unlock(&parent->d_inode->i_mutex);
- }
if (err) {
dput(dentry);
dentry = ERR_PTR(err);
}
}
-
+ mutex_unlock(&parent->d_inode->i_mutex);
return dentry;
}
@@ -184,6 +179,7 @@ fill_with_dentries(void *buf, const char
{
struct reiserfs_dentry_buf *dbuf = buf;
struct dentry *dentry;
+ WARN_ON_ONCE(!mutex_is_locked(&dbuf->xadir->d_inode->i_mutex));
if (dbuf->count == ARRAY_SIZE(dbuf->dentries))
return -ENOSPC;
@@ -349,6 +345,7 @@ static struct dentry *xattr_lookup(struc
if (IS_ERR(xadir))
return ERR_CAST(xadir);
+ mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR);
xafile = lookup_one_len(name, xadir, strlen(name));
if (IS_ERR(xafile)) {
err = PTR_ERR(xafile);
@@ -360,18 +357,15 @@ static struct dentry *xattr_lookup(struc
if (!xafile->d_inode) {
err = -ENODATA;
- if (xattr_may_create(flags)) {
- mutex_lock_nested(&xadir->d_inode->i_mutex,
- I_MUTEX_XATTR);
+ if (xattr_may_create(flags))
err = xattr_create(xadir->d_inode, xafile,
0700|S_IFREG);
- mutex_unlock(&xadir->d_inode->i_mutex);
- }
}
if (err)
dput(xafile);
out:
+ mutex_unlock(&xadir->d_inode->i_mutex);
dput(xadir);
if (err)
return ERR_PTR(err);
@@ -435,6 +429,7 @@ static int lookup_and_delete_xattr(struc
if (IS_ERR(xadir))
return PTR_ERR(xadir);
+ mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR);
dentry = lookup_one_len(name, xadir, strlen(name));
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
@@ -442,14 +437,13 @@ static int lookup_and_delete_xattr(struc
}
if (dentry->d_inode) {
- mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR);
err = xattr_unlink(xadir->d_inode, dentry);
- mutex_unlock(&xadir->d_inode->i_mutex);
update_ctime(inode);
}
dput(dentry);
out_dput:
+ mutex_unlock(&xadir->d_inode->i_mutex);
dput(xadir);
return err;
}
@@ -906,9 +900,9 @@ static int create_privroot(struct dentry
{
int err;
struct inode *inode = dentry->d_parent->d_inode;
- mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
+ WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
+
err = xattr_mkdir(inode, dentry, 0700);
- mutex_unlock(&inode->i_mutex);
if (err) {
dput(dentry);
dentry = NULL;
@@ -980,6 +974,7 @@ int reiserfs_xattr_init(struct super_blo
/* If we don't have the privroot located yet - go find it */
if (!REISERFS_SB(s)->priv_root) {
struct dentry *dentry;
+ mutex_lock_nested(&s->s_root->d_inode->i_mutex, I_MUTEX_CHILD);
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
strlen(PRIVROOT_NAME));
if (!IS_ERR(dentry)) {
@@ -993,6 +988,7 @@ int reiserfs_xattr_init(struct super_blo
}
} else
err = PTR_ERR(dentry);
+ mutex_unlock(&s->s_root->d_inode->i_mutex);
if (!err && dentry) {
s->s_root->d_op = &xattr_lookup_poison_ops;
--
Jeff Mahoney
SUSE Labs
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-01 16:11 [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len Jeff Mahoney @ 2009-05-01 16:37 ` Alexander Beregalov 2009-05-01 19:56 ` Andrew Morton 2009-05-03 8:52 ` Al Viro 2 siblings, 0 replies; 12+ messages in thread From: Alexander Beregalov @ 2009-05-01 16:37 UTC (permalink / raw) To: Jeff Mahoney Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, David 2009/5/1 Jeff Mahoney <jeffm@suse.com>: > 2.6.30-rc3 introduced some sanity checks in the VFS code to avoid NFS > bugs by ensuring that lookup_one_len is always called under i_mutex. > > This patch expands the i_mutex locking to enclose lookup_one_len. This was > always required, but not not enforced in the reiserfs code since it > does locking around the xattr interactions with the xattr_sem. > > This is obvious enough, but it survived an overnight 50 thread ACL test. > > Signed-off-by: Jeff Mahoney <jeffm@suse.com> Tested-by: Alexander Beregalov <a.beregalov@gmail.com> It works, thanks. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-01 16:11 [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len Jeff Mahoney 2009-05-01 16:37 ` Alexander Beregalov @ 2009-05-01 19:56 ` Andrew Morton 2009-05-01 20:36 ` Jeff Mahoney 2009-05-03 8:52 ` Al Viro 2 siblings, 1 reply; 12+ messages in thread From: Andrew Morton @ 2009-05-01 19:56 UTC (permalink / raw) To: Jeff Mahoney Cc: linux-kernel, reiserfs-devel, viro, a.beregalov, david, Rafael J. Wysocki On Fri, 01 May 2009 12:11:12 -0400 Jeff Mahoney <jeffm@suse.com> wrote: > 2.6.30-rc3 introduced some sanity checks in the VFS code to avoid NFS > bugs by ensuring that lookup_one_len is always called under i_mutex. > > This patch expands the i_mutex locking to enclose lookup_one_len. This was > always required, but not not enforced in the reiserfs code since it > does locking around the xattr interactions with the xattr_sem. cool, so this will fix all those backtraces people have been reporting coming out of the reiserfs xattr code lately? > This is obvious enough, but it survived an overnight 50 thread ACL test. That sounds a bit pessimistic. I think I'll s/but/and/ ;) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-01 19:56 ` Andrew Morton @ 2009-05-01 20:36 ` Jeff Mahoney 0 siblings, 0 replies; 12+ messages in thread From: Jeff Mahoney @ 2009-05-01 20:36 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, reiserfs-devel, viro, a.beregalov, david, Rafael J. Wysocki -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Andrew Morton wrote: > On Fri, 01 May 2009 12:11:12 -0400 > Jeff Mahoney <jeffm@suse.com> wrote: > >> 2.6.30-rc3 introduced some sanity checks in the VFS code to avoid NFS >> bugs by ensuring that lookup_one_len is always called under i_mutex. >> >> This patch expands the i_mutex locking to enclose lookup_one_len. This was >> always required, but not not enforced in the reiserfs code since it >> does locking around the xattr interactions with the xattr_sem. > > cool, so this will fix all those backtraces people have been reporting > coming out of the reiserfs xattr code lately? Yes. >> This is obvious enough, but it survived an overnight 50 thread ACL test. > > That sounds a bit pessimistic. I think I'll s/but/and/ ;) Yeah, that's more accurate. :) - -Jeff - -- Jeff Mahoney SUSE Labs -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAkn7XU4ACgkQLPWxlyuTD7JOAgCfcVV+kowmYbaBKNCZG7BfNx3V 9dwAoKGB7Uu2RkwXtkpaaCi2ADtQszC1 =B4is -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-01 16:11 [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len Jeff Mahoney 2009-05-01 16:37 ` Alexander Beregalov 2009-05-01 19:56 ` Andrew Morton @ 2009-05-03 8:52 ` Al Viro 2009-05-03 9:15 ` Al Viro 2009-05-04 5:01 ` Jeff Mahoney 2 siblings, 2 replies; 12+ messages in thread From: Al Viro @ 2009-05-03 8:52 UTC (permalink / raw) To: Jeff Mahoney Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, Alexander Beregalov, David On Fri, May 01, 2009 at 12:11:12PM -0400, Jeff Mahoney wrote: > 2.6.30-rc3 introduced some sanity checks in the VFS code to avoid NFS > bugs by ensuring that lookup_one_len is always called under i_mutex. > > This patch expands the i_mutex locking to enclose lookup_one_len. This was > always required, but not not enforced in the reiserfs code since it > does locking around the xattr interactions with the xattr_sem. > > This is obvious enough, but it survived an overnight 50 thread ACL test. It's not enough, unfortunately ;-/ It deals with the warning, but it leaves an actual hole in there. Look: what happens if we mount it r/o without that directory and then remount r/w? We get dentry for privroot, hash it (negative at that point), then do actual mkdir, unlock root and modify the ->d_compare() of root to reject lookups on that sucker. Too late - in the meanwhile lookups might very well come and find privroot in dcache. BTW, the way ->d_compare() is done in there is rather dumb - if (q1 == &priv_root->d_name) return -ENOENT; ... would do just as well. Why don't we do that lookup *once* (on ->get_sb(), before anything can come and race with us), and then just keep negative dentry if the directory hadn't been around? And set d_compare() for root immediately after that lookup... I've applied your patch as-is, and unless you have objections to the variant above I'll do that as incremental. Comments? ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-03 8:52 ` Al Viro @ 2009-05-03 9:15 ` Al Viro 2009-05-03 10:06 ` Al Viro 2009-05-04 4:51 ` Jeff Mahoney 2009-05-04 5:01 ` Jeff Mahoney 1 sibling, 2 replies; 12+ messages in thread From: Al Viro @ 2009-05-03 9:15 UTC (permalink / raw) To: Jeff Mahoney Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, Alexander Beregalov, David On Sun, May 03, 2009 at 09:52:36AM +0100, Al Viro wrote: > On Fri, May 01, 2009 at 12:11:12PM -0400, Jeff Mahoney wrote: > > 2.6.30-rc3 introduced some sanity checks in the VFS code to avoid NFS > > bugs by ensuring that lookup_one_len is always called under i_mutex. > > > > This patch expands the i_mutex locking to enclose lookup_one_len. This was > > always required, but not not enforced in the reiserfs code since it > > does locking around the xattr interactions with the xattr_sem. > > > > This is obvious enough, but it survived an overnight 50 thread ACL test. > > It's not enough, unfortunately ;-/ It deals with the warning, but it > leaves an actual hole in there. > > Look: what happens if we mount it r/o without that directory and then > remount r/w? We get dentry for privroot, hash it (negative at that point), > then do actual mkdir, unlock root and modify the ->d_compare() of root > to reject lookups on that sucker. Too late - in the meanwhile lookups > might very well come and find privroot in dcache. > > BTW, the way ->d_compare() is done in there is rather dumb - > if (q1 == &priv_root->d_name) > return -ENOENT; > ... > would do just as well. Why don't we do that lookup *once* (on ->get_sb(), > before anything can come and race with us), and then just keep negative > dentry if the directory hadn't been around? And set d_compare() for root > immediately after that lookup... > > I've applied your patch as-is, and unless you have objections to the > variant above I'll do that as incremental. Comments? BTW, what in the name of everything unholy is ->xattr_root? Never assigned a non-NULL value... ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-03 9:15 ` Al Viro @ 2009-05-03 10:06 ` Al Viro 2009-05-04 4:51 ` Jeff Mahoney 1 sibling, 0 replies; 12+ messages in thread From: Al Viro @ 2009-05-03 10:06 UTC (permalink / raw) To: Jeff Mahoney Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, Alexander Beregalov, David On Sun, May 03, 2009 at 10:15:08AM +0100, Al Viro wrote: > > I've applied your patch as-is, and unless you have objections to the > > variant above I'll do that as incremental. Comments? > > BTW, what in the name of everything unholy is ->xattr_root? Never > assigned a non-NULL value... Looks like your xattr journalling is b0rken - the check in there should be that for ->priv_root, AFAICS. Anyway, promised incremental follows (FWIW, it's commit ff4559 in git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6.git/ on #untested). [PATCH] Always lookup priv_root on reiserfs mount and keep it ... even if it's a negative dentry. That way we can set ->d_op on root before anyone could race with us. Simplify d_compare(), while we are at it. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/reiserfs/super.c | 6 ++- fs/reiserfs/xattr.c | 86 +++++++++++++++++----------------------- include/linux/reiserfs_xattr.h | 1 + 3 files changed, 41 insertions(+), 52 deletions(-) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 5d0064d..f45cac9 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1845,7 +1845,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) goto error; } - if ((errval = reiserfs_xattr_init(s, s->s_flags))) { + if ((errval = reiserfs_lookup_privroot(s)) || + (errval = reiserfs_xattr_init(s, s->s_flags))) { dput(s->s_root); s->s_root = NULL; goto error; @@ -1858,7 +1859,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) reiserfs_info(s, "using 3.5.x disk format\n"); } - if ((errval = reiserfs_xattr_init(s, s->s_flags))) { + if ((errval = reiserfs_lookup_privroot(s)) || + (errval = reiserfs_xattr_init(s, s->s_flags))) { dput(s->s_root); s->s_root = NULL; goto error; diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 31a3dbb..2891f78 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -903,16 +903,19 @@ static int create_privroot(struct dentry *dentry) WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex)); err = xattr_mkdir(inode, dentry, 0700); - if (err) { - dput(dentry); - dentry = NULL; + if (err || !dentry->d_inode) { + reiserfs_warning(dentry->d_sb, "jdm-20006", + "xattrs/ACLs enabled and couldn't " + "find/create .reiserfs_priv. " + "Failing mount."); + return -EOPNOTSUPP; } - if (dentry && dentry->d_inode) - reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " - "storage.\n", PRIVROOT_NAME); + dentry->d_inode->i_flags |= S_PRIVATE; + reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " + "storage.\n", PRIVROOT_NAME); - return err; + return 0; } static int xattr_mount_check(struct super_block *s) @@ -944,11 +947,9 @@ static int xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) { struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root; - if (name->len == priv_root->d_name.len && - name->hash == priv_root->d_name.hash && - !memcmp(name->name, priv_root->d_name.name, name->len)) { + if (container_of(q1, struct dentry, d_name) == priv_root) return -ENOENT; - } else if (q1->len == name->len && + if (q1->len == name->len && !memcmp(q1->name, name->name, name->len)) return 0; return 1; @@ -958,6 +959,27 @@ static const struct dentry_operations xattr_lookup_poison_ops = { .d_compare = xattr_lookup_poison, }; +int reiserfs_lookup_privroot(struct super_block *s) +{ + struct dentry *dentry; + int err = 0; + + /* If we don't have the privroot located yet - go find it */ + mutex_lock(&s->s_root->d_inode->i_mutex); + dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, + strlen(PRIVROOT_NAME)); + if (!IS_ERR(dentry)) { + REISERFS_SB(s)->priv_root = dentry; + s->s_root->d_op = &xattr_lookup_poison_ops; + if (dentry->d_inode) + dentry->d_inode->i_flags |= S_PRIVATE; + } else + err = PTR_ERR(dentry); + mutex_unlock(&s->s_root->d_inode->i_mutex); + + return err; +} + /* We need to take a copy of the mount flags since things like * MS_RDONLY don't get set until *after* we're called. * mount_flags != mount_options */ @@ -969,48 +991,12 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) err = xattr_mount_check(s); if (err) goto error; -#endif - /* If we don't have the privroot located yet - go find it */ - if (!REISERFS_SB(s)->priv_root) { - struct dentry *dentry; - mutex_lock_nested(&s->s_root->d_inode->i_mutex, I_MUTEX_CHILD); - dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, - strlen(PRIVROOT_NAME)); - if (!IS_ERR(dentry)) { -#ifdef CONFIG_REISERFS_FS_XATTR - if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) - err = create_privroot(dentry); -#endif - if (!dentry->d_inode) { - dput(dentry); - dentry = NULL; - } - } else - err = PTR_ERR(dentry); + if (!REISERFS_SB(s)->priv_root->d_inode && !(mount_flags & MS_RDONLY)) { + mutex_lock(&s->s_root->d_inode->i_mutex); + err = create_privroot(REISERFS_SB(s)->priv_root); mutex_unlock(&s->s_root->d_inode->i_mutex); - - if (!err && dentry) { - s->s_root->d_op = &xattr_lookup_poison_ops; - dentry->d_inode->i_flags |= S_PRIVATE; - REISERFS_SB(s)->priv_root = dentry; -#ifdef CONFIG_REISERFS_FS_XATTR - /* xattrs are unavailable */ - } else if (!(mount_flags & MS_RDONLY)) { - /* If we're read-only it just means that the dir - * hasn't been created. Not an error -- just no - * xattrs on the fs. We'll check again if we - * go read-write */ - reiserfs_warning(s, "jdm-20006", - "xattrs/ACLs enabled and couldn't " - "find/create .reiserfs_priv. " - "Failing mount."); - err = -EOPNOTSUPP; -#endif - } } - -#ifdef CONFIG_REISERFS_FS_XATTR if (!err) s->s_xattr = reiserfs_xattr_handlers; diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h index dcae01e..fea1a8e 100644 --- a/include/linux/reiserfs_xattr.h +++ b/include/linux/reiserfs_xattr.h @@ -38,6 +38,7 @@ struct nameidata; int reiserfs_xattr_register_handlers(void) __init; void reiserfs_xattr_unregister_handlers(void); int reiserfs_xattr_init(struct super_block *sb, int mount_flags); +int reiserfs_lookup_privroot(struct super_block *sb); int reiserfs_delete_xattrs(struct inode *inode); int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); -- 1.5.6.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-03 9:15 ` Al Viro 2009-05-03 10:06 ` Al Viro @ 2009-05-04 4:51 ` Jeff Mahoney 2009-05-04 6:13 ` Al Viro 1 sibling, 1 reply; 12+ messages in thread From: Jeff Mahoney @ 2009-05-04 4:51 UTC (permalink / raw) To: Al Viro Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, Alexander Beregalov, David -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Al Viro wrote: > On Sun, May 03, 2009 at 09:52:36AM +0100, Al Viro wrote: >> On Fri, May 01, 2009 at 12:11:12PM -0400, Jeff Mahoney wrote: >>> 2.6.30-rc3 introduced some sanity checks in the VFS code to avoid NFS >>> bugs by ensuring that lookup_one_len is always called under i_mutex. >>> >>> This patch expands the i_mutex locking to enclose lookup_one_len. This was >>> always required, but not not enforced in the reiserfs code since it >>> does locking around the xattr interactions with the xattr_sem. >>> >>> This is obvious enough, but it survived an overnight 50 thread ACL test. >> It's not enough, unfortunately ;-/ It deals with the warning, but it >> leaves an actual hole in there. >> >> Look: what happens if we mount it r/o without that directory and then >> remount r/w? We get dentry for privroot, hash it (negative at that point), >> then do actual mkdir, unlock root and modify the ->d_compare() of root >> to reject lookups on that sucker. Too late - in the meanwhile lookups >> might very well come and find privroot in dcache. >> >> BTW, the way ->d_compare() is done in there is rather dumb - >> if (q1 == &priv_root->d_name) >> return -ENOENT; >> ... >> would do just as well. Why don't we do that lookup *once* (on ->get_sb(), >> before anything can come and race with us), and then just keep negative >> dentry if the directory hadn't been around? And set d_compare() for root >> immediately after that lookup... >> >> I've applied your patch as-is, and unless you have objections to the >> variant above I'll do that as incremental. Comments? > > BTW, what in the name of everything unholy is ->xattr_root? Never > assigned a non-NULL value... Huh. I didn't see that still in there. That's an artifact of an earlier version of the code where I kept a reference to /.reiserfs_priv/xattrs. Then I decided that .reiserfs_priv was all I needed to cache (to avoid recursive i_mutex locking on the fs root) and dropped the caching of xattrs. Looks like it didn't get totally cleared out. - -Jeff -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAkn+dEgACgkQLPWxlyuTD7J4/ACggM4bSYzp8zuS8KXf2WaFSpS4 458An1YCcTf4hYXjFXuU8ZS2eEWJCpaa =ZDpK -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-04 4:51 ` Jeff Mahoney @ 2009-05-04 6:13 ` Al Viro 2009-05-04 16:40 ` Jeff Mahoney 0 siblings, 1 reply; 12+ messages in thread From: Al Viro @ 2009-05-04 6:13 UTC (permalink / raw) To: Jeff Mahoney Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, Alexander Beregalov, David On Mon, May 04, 2009 at 12:51:20AM -0400, Jeff Mahoney wrote: > Huh. I didn't see that still in there. That's an artifact of an earlier > version of the code where I kept a reference to /.reiserfs_priv/xattrs. > Then I decided that .reiserfs_priv was all I needed to cache (to avoid > recursive i_mutex locking on the fs root) and dropped the caching of > xattrs. Looks like it didn't get totally cleared out. It's not that simple ;-/ You check it in journalling code, AFAICS in order to decide how much will that sucker take (due to extra mkdir?) and something will need to be done with that check. Anyway, I'm going to push all that stuff to #for-next, so that -next would pick it. I have *not* touched the xattr_root logics, so if you could do that on top of your patch + my incremental... ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-04 6:13 ` Al Viro @ 2009-05-04 16:40 ` Jeff Mahoney 2009-05-05 19:29 ` Jeff Mahoney 0 siblings, 1 reply; 12+ messages in thread From: Jeff Mahoney @ 2009-05-04 16:40 UTC (permalink / raw) To: Al Viro Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, Alexander Beregalov, David -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Al Viro wrote: > On Mon, May 04, 2009 at 12:51:20AM -0400, Jeff Mahoney wrote: > >> Huh. I didn't see that still in there. That's an artifact of an earlier >> version of the code where I kept a reference to /.reiserfs_priv/xattrs. >> Then I decided that .reiserfs_priv was all I needed to cache (to avoid >> recursive i_mutex locking on the fs root) and dropped the caching of >> xattrs. Looks like it didn't get totally cleared out. > > It's not that simple ;-/ You check it in journalling code, AFAICS in order > to decide how much will that sucker take (due to extra mkdir?) and something > will need to be done with that check. Yes, it's for an extra mkdir. Now that I've gotten some sleep and looked at the code again, I see what you're saying. At least it's broken in a performance way instead of causing a system crash or data corruption. > Anyway, I'm going to push all that stuff to #for-next, so that -next would > pick it. I have *not* touched the xattr_root logics, so if you could do > that on top of your patch + my incremental... Ok, I'll fix that up and get some testing in. - -Jeff - -- Jeff Mahoney SUSE Labs -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAkn/Gn4ACgkQLPWxlyuTD7KclACeLNAOawW5fDxc2CqGZz4NUXpY 21AAoJdsK3EEPweBCuv1131j3Lm8x3lk =0Iqb -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-04 16:40 ` Jeff Mahoney @ 2009-05-05 19:29 ` Jeff Mahoney 0 siblings, 0 replies; 12+ messages in thread From: Jeff Mahoney @ 2009-05-05 19:29 UTC (permalink / raw) To: Al Viro Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, Alexander Beregalov, David Jeff Mahoney wrote: > Al Viro wrote: >> On Mon, May 04, 2009 at 12:51:20AM -0400, Jeff Mahoney wrote: > >>> Huh. I didn't see that still in there. That's an artifact of an earlier >>> version of the code where I kept a reference to /.reiserfs_priv/xattrs. >>> Then I decided that .reiserfs_priv was all I needed to cache (to avoid >>> recursive i_mutex locking on the fs root) and dropped the caching of >>> xattrs. Looks like it didn't get totally cleared out. >> It's not that simple ;-/ You check it in journalling code, AFAICS in order >> to decide how much will that sucker take (due to extra mkdir?) and something >> will need to be done with that check. > > Yes, it's for an extra mkdir. Now that I've gotten some sleep and looked > at the code again, I see what you're saying. At least it's broken in a > performance way instead of causing a system crash or data corruption. > >> Anyway, I'm going to push all that stuff to #for-next, so that -next would >> pick it. I have *not* touched the xattr_root logics, so if you could do >> that on top of your patch + my incremental... > > Ok, I'll fix that up and get some testing in. Here's the patch to fix up the xattr root caching. I have two more that do some cleanups that I'll post separately. The early load of the privroot means we can get rid of some of the mess with hiding the entry during readdir and lookup. I'll send all three as a series, separately as well. -Jeff --- The xattr_root caching was broken from my previous patch set. It wouldn't cause corruption, but could cause decreased performance due to allocating a larger chunk of the journal (~ 27 blocks) than it would actually use. This patch loads the xattr root dentry at xattr initialization and creates it on-demand. Since we're using the cached dentry, there's no point in keeping lookup_or_create_dir around, so that's removed. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/reiserfs/xattr.c | 73 +++++++++++++++++++++++++---------------- include/linux/reiserfs_fs_sb.h | 2 - include/linux/reiserfs_xattr.h | 2 - 3 files changed, 48 insertions(+), 29 deletions(-) --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -113,36 +113,28 @@ static int xattr_rmdir(struct inode *dir #define xattr_may_create(flags) (!flags || flags & XATTR_CREATE) -/* Returns and possibly creates the xattr dir. */ -static struct dentry *lookup_or_create_dir(struct dentry *parent, - const char *name, int flags) +static struct dentry *open_xa_root(struct super_block *sb, int flags) { - struct dentry *dentry; - BUG_ON(!parent); + struct dentry *privroot = REISERFS_SB(sb)->priv_root; + struct dentry *xaroot; + if (!privroot->d_inode) + return ERR_PTR(-ENODATA); - mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_XATTR); - dentry = lookup_one_len(name, parent, strlen(name)); - if (!IS_ERR(dentry) && !dentry->d_inode) { - int err = -ENODATA; + mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR); + xaroot = dget(REISERFS_SB(sb)->xattr_root); + if (!xaroot->d_inode) { + int err = -ENODATA; if (xattr_may_create(flags)) - err = xattr_mkdir(parent->d_inode, dentry, 0700); - + err = xattr_mkdir(privroot->d_inode, xaroot, 0700); if (err) { - dput(dentry); - dentry = ERR_PTR(err); + dput(xaroot); + xaroot = ERR_PTR(err); } } - mutex_unlock(&parent->d_inode->i_mutex); - return dentry; -} -static struct dentry *open_xa_root(struct super_block *sb, int flags) -{ - struct dentry *privroot = REISERFS_SB(sb)->priv_root; - if (!privroot) - return ERR_PTR(-ENODATA); - return lookup_or_create_dir(privroot, XAROOT_NAME, flags); + mutex_unlock(&privroot->d_inode->i_mutex); + return xaroot; } static struct dentry *open_xa_dir(const struct inode *inode, int flags) @@ -158,10 +150,22 @@ static struct dentry *open_xa_dir(const le32_to_cpu(INODE_PKEY(inode)->k_objectid), inode->i_generation); - xadir = lookup_or_create_dir(xaroot, namebuf, flags); + mutex_lock_nested(&xaroot->d_inode->i_mutex, I_MUTEX_XATTR); + + xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf)); + if (!IS_ERR(xadir) && !xadir->d_inode) { + int err = -ENODATA; + if (xattr_may_create(flags)) + err = xattr_mkdir(xaroot->d_inode, xadir, 0700); + if (err) { + dput(xadir); + xadir = ERR_PTR(err); + } + } + + mutex_unlock(&xaroot->d_inode->i_mutex); dput(xaroot); return xadir; - } /* The following are side effects of other operations that aren't explicitly @@ -986,19 +990,33 @@ int reiserfs_lookup_privroot(struct supe int reiserfs_xattr_init(struct super_block *s, int mount_flags) { int err = 0; + struct dentry *privroot = REISERFS_SB(s)->priv_root; #ifdef CONFIG_REISERFS_FS_XATTR err = xattr_mount_check(s); if (err) goto error; - if (!REISERFS_SB(s)->priv_root->d_inode && !(mount_flags & MS_RDONLY)) { + if (!privroot->d_inode && !(mount_flags & MS_RDONLY)) { mutex_lock(&s->s_root->d_inode->i_mutex); err = create_privroot(REISERFS_SB(s)->priv_root); mutex_unlock(&s->s_root->d_inode->i_mutex); } - if (!err) + + if (privroot->d_inode) { s->s_xattr = reiserfs_xattr_handlers; + mutex_lock(&privroot->d_inode->i_mutex); + if (!REISERFS_SB(s)->xattr_root) { + struct dentry *dentry; + dentry = lookup_one_len(XAROOT_NAME, privroot, + strlen(XAROOT_NAME)); + if (!IS_ERR(dentry)) + REISERFS_SB(s)->xattr_root = dentry; + else + err = PTR_ERR(dentry); + } + mutex_unlock(&privroot->d_inode->i_mutex); + } error: if (err) { @@ -1008,11 +1026,12 @@ error: #endif /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */ - s->s_flags = s->s_flags & ~MS_POSIXACL; #ifdef CONFIG_REISERFS_FS_POSIX_ACL if (reiserfs_posixacl(s)) s->s_flags |= MS_POSIXACL; + else #endif + s->s_flags &= ~MS_POSIXACL; return err; } --- a/include/linux/reiserfs_fs_sb.h +++ b/include/linux/reiserfs_fs_sb.h @@ -402,7 +402,7 @@ struct reiserfs_sb_info { int reserved_blocks; /* amount of blocks reserved for further allocations */ spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */ struct dentry *priv_root; /* root of /.reiserfs_priv */ - struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */ + struct dentry *xattr_root; /* root of /.reiserfs_priv/xattrs */ int j_errno; #ifdef CONFIG_QUOTA char *s_qf_names[MAXQUOTAS]; --- a/include/linux/reiserfs_xattr.h +++ b/include/linux/reiserfs_xattr.h @@ -98,7 +98,7 @@ static inline size_t reiserfs_xattr_jcre if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) { nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); - if (REISERFS_SB(inode->i_sb)->xattr_root == NULL) + if (!REISERFS_SB(inode->i_sb)->xattr_root->d_inode) nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); } -- Jeff Mahoney SUSE Labs ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len 2009-05-03 8:52 ` Al Viro 2009-05-03 9:15 ` Al Viro @ 2009-05-04 5:01 ` Jeff Mahoney 1 sibling, 0 replies; 12+ messages in thread From: Jeff Mahoney @ 2009-05-04 5:01 UTC (permalink / raw) To: Al Viro Cc: Linux Kernel Mailing List, ReiserFS Mailing List, Andrew Morton, Al Viro, Alexander Beregalov, David -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Al Viro wrote: > On Fri, May 01, 2009 at 12:11:12PM -0400, Jeff Mahoney wrote: >> 2.6.30-rc3 introduced some sanity checks in the VFS code to avoid NFS >> bugs by ensuring that lookup_one_len is always called under i_mutex. >> >> This patch expands the i_mutex locking to enclose lookup_one_len. This was >> always required, but not not enforced in the reiserfs code since it >> does locking around the xattr interactions with the xattr_sem. >> >> This is obvious enough, but it survived an overnight 50 thread ACL test. > > It's not enough, unfortunately ;-/ It deals with the warning, but it > leaves an actual hole in there. > > Look: what happens if we mount it r/o without that directory and then > remount r/w? We get dentry for privroot, hash it (negative at that point), > then do actual mkdir, unlock root and modify the ->d_compare() of root > to reject lookups on that sucker. Too late - in the meanwhile lookups > might very well come and find privroot in dcache. > > BTW, the way ->d_compare() is done in there is rather dumb - > if (q1 == &priv_root->d_name) > return -ENOENT; > ... > would do just as well. Why don't we do that lookup *once* (on ->get_sb(), > before anything can come and race with us), and then just keep negative > dentry if the directory hadn't been around? And set d_compare() for root > immediately after that lookup... > > I've applied your patch as-is, and unless you have objections to the > variant above I'll do that as incremental. Comments? Of course you're right about the lookup hole. The lookup during remount is from when the code didn't enable xattrs unconditionally for security and trusted attributes. The privroot would only be created when mounted read-write with -oacl and/or -ouser_xattr. Now xattrs are enabled uncondtionally, so any read-write mount will create that if xattrs are enabled in the kernel. It used to avoid caching a negative lookup that would never get used. I don't have any objections to any of your suggestions. Thanks! - -Jeff -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAkn+dp0ACgkQLPWxlyuTD7KuwQCgmrYQhuDy+HylXPL46Yb2R9Y+ Fr0AoIKRyL4mX1wCR+R9WN74zULTrbXT =LSDi -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2009-05-05 19:30 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-05-01 16:11 [PATCH] reiserfs: Expand i_mutex to enclose lookup_one_len Jeff Mahoney 2009-05-01 16:37 ` Alexander Beregalov 2009-05-01 19:56 ` Andrew Morton 2009-05-01 20:36 ` Jeff Mahoney 2009-05-03 8:52 ` Al Viro 2009-05-03 9:15 ` Al Viro 2009-05-03 10:06 ` Al Viro 2009-05-04 4:51 ` Jeff Mahoney 2009-05-04 6:13 ` Al Viro 2009-05-04 16:40 ` Jeff Mahoney 2009-05-05 19:29 ` Jeff Mahoney 2009-05-04 5:01 ` Jeff Mahoney
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox