From: Jeff Mahoney <jeffm@suse.com>
To: a.righi@cineca.it
Cc: Andrew Morton <akpm@linux-foundation.org>,
"Vladimir V. Saveliev" <vs@namesys.com>,
linux-kernel@vger.kernel.org, reiserfs-dev@namesys.com,
Edward Shishkin <edward@namesys.com>,
zam@clusterfs.com, ak@suse.de
Subject: [PATCH] reiserfs: fix xattr root locking/refcount bug
Date: Sat, 21 Apr 2007 11:26:31 -0400 [thread overview]
Message-ID: <462A2D27.3060809@suse.com> (raw)
In-Reply-To: <462A2107.6060902@suse.de>
The listxattr() and getxattr() operations are only protected by a read
lock. As a result, if either of these operations run in parallel, a race
condition exists where the xattr_root will end up being cached twice,
which results in the leaking of a reference and a BUG() on umount.
This patch refactors get_xa_root(), __get_xa_root(), and
create_xa_root(), into one get_xa_root() function that takes
the appropriate locking around the entire critical section.
Changes from initial version:
With the previous version, established file systems worked, but freshly
created file systems would fail to mount due to a circular dependency
with the privroot. New inodes created in directories without I_PRIVATE
will inherit the parent's default ACL. When creating the privroot,
we'd get -EOPNOTSUPP due to the privroot not existing while looking up
the default ACL. The old get_xa_dir() only checked for a negative
dentry and returned -ENODATA. This version treats a missing privroot
as -ENODATA. This is safe since xattrs are disabled automatically in
reiserfs_xattr_init() when the privroot can't be created or found.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
fs/reiserfs/xattr.c | 92 +++++++++++++---------------------------------------
1 file changed, 24 insertions(+), 68 deletions(-)
--- a/fs/reiserfs/xattr.c 2007-04-21 10:15:00.000000000 -0400
+++ b/fs/reiserfs/xattr.c 2007-04-21 11:21:02.000000000 -0400
@@ -54,82 +54,48 @@
static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
*prefix);
-static struct dentry *create_xa_root(struct super_block *sb)
+/* Returns the dentry referring to the root of the extended attribute
+ * directory tree. If it has already been retrieved, it is used. If it
+ * hasn't been created and the flags indicate creation is allowed, we
+ * attempt to create it. On error, we return a pointer-encoded error.
+ */
+static struct dentry *get_xa_root(struct super_block *sb, int flags)
{
struct dentry *privroot = dget(REISERFS_SB(sb)->priv_root);
struct dentry *xaroot;
/* This needs to be created at mount-time */
if (!privroot)
- return ERR_PTR(-EOPNOTSUPP);
+ return ERR_PTR(-ENODATA);
- xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME));
- if (IS_ERR(xaroot)) {
+ mutex_lock(&privroot->d_inode->i_mutex);
+ if (REISERFS_SB(sb)->xattr_root) {
+ xaroot = dget(REISERFS_SB(sb)->xattr_root);
goto out;
- } else if (!xaroot->d_inode) {
- int err;
- mutex_lock(&privroot->d_inode->i_mutex);
- err =
- privroot->d_inode->i_op->mkdir(privroot->d_inode, xaroot,
- 0700);
- mutex_unlock(&privroot->d_inode->i_mutex);
-
- if (err) {
- dput(xaroot);
- dput(privroot);
- return ERR_PTR(err);
- }
- REISERFS_SB(sb)->xattr_root = dget(xaroot);
}
- out:
- dput(privroot);
- return xaroot;
-}
-
-/* This will return a dentry, or error, refering to the xa root directory.
- * If the xa root doesn't exist yet, the dentry will be returned without
- * an associated inode. This dentry can be used with ->mkdir to create
- * the xa directory. */
-static struct dentry *__get_xa_root(struct super_block *s)
-{
- struct dentry *privroot = dget(REISERFS_SB(s)->priv_root);
- struct dentry *xaroot = NULL;
-
- if (IS_ERR(privroot) || !privroot)
- return privroot;
-
xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME));
if (IS_ERR(xaroot)) {
goto out;
} else if (!xaroot->d_inode) {
- dput(xaroot);
- xaroot = NULL;
- goto out;
+ int err = -ENODATA;
+ if (flags == 0 || flags & XATTR_CREATE)
+ err = privroot->d_inode->i_op->mkdir(privroot->d_inode,
+ xaroot, 0700);
+ if (err) {
+ dput(xaroot);
+ xaroot = ERR_PTR(err);
+ goto out;
+ }
}
-
- REISERFS_SB(s)->xattr_root = dget(xaroot);
+ REISERFS_SB(sb)->xattr_root = dget(xaroot);
out:
+ mutex_unlock(&privroot->d_inode->i_mutex);
dput(privroot);
return xaroot;
}
-/* Returns the dentry (or NULL) referring to the root of the extended
- * attribute directory tree. If it has already been retrieved, it is used.
- * Otherwise, we attempt to retrieve it from disk. It may also return
- * a pointer-encoded error.
- */
-static inline struct dentry *get_xa_root(struct super_block *s)
-{
- struct dentry *dentry = dget(REISERFS_SB(s)->xattr_root);
-
- if (!dentry)
- dentry = __get_xa_root(s);
-
- return dentry;
-}
-
/* Opens the directory corresponding to the inode's extended attribute store.
* If flags allow, the tree to the directory may be created. If creation is
* prohibited, -ENODATA is returned. */
@@ -138,21 +104,11 @@ static struct dentry *open_xa_dir(const
struct dentry *xaroot, *xadir;
char namebuf[17];
- xaroot = get_xa_root(inode->i_sb);
- if (IS_ERR(xaroot)) {
+ xaroot = get_xa_root(inode->i_sb, flags);
+ if (IS_ERR(xaroot))
return xaroot;
- } else if (!xaroot) {
- if (flags == 0 || flags & XATTR_CREATE) {
- xaroot = create_xa_root(inode->i_sb);
- if (IS_ERR(xaroot))
- return xaroot;
- }
- if (!xaroot)
- return ERR_PTR(-ENODATA);
- }
/* ok, we have xaroot open */
-
snprintf(namebuf, sizeof(namebuf), "%X.%X",
le32_to_cpu(INODE_PKEY(inode)->k_objectid),
inode->i_generation);
@@ -821,7 +777,7 @@ int reiserfs_delete_xattrs(struct inode
/* Leftovers besides . and .. -- that's not good. */
if (dir->d_inode->i_nlink <= 2) {
- root = get_xa_root(inode->i_sb);
+ root = get_xa_root(inode->i_sb, XATTR_REPLACE);
reiserfs_write_lock_xattrs(inode->i_sb);
err = vfs_rmdir(root->d_inode, dir);
reiserfs_write_unlock_xattrs(inode->i_sb);
--
Jeff Mahoney
SUSE Labs
next prev parent reply other threads:[~2007-04-21 15:26 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20070413095219.02075323.akpm@linux-foundation.org>
[not found] ` <462536B2.5060308@users.sourceforge.net>
[not found] ` <c04ebacf0704180152qdc72fcdnd0755dbf070b40d2@mail.gmail.com>
2007-04-18 14:16 ` Fwd: Fw: [2.6.20.4] BUG: dentry xattrs still in use in shrink_dcache_for_umount() with reiserfs Vladimir V. Saveliev
2007-04-18 15:00 ` Jeff Mahoney
2007-04-21 0:07 ` Andrew Morton
2007-04-21 1:45 ` Jeff Mahoney
2007-04-21 13:17 ` Andrea Righi
2007-04-21 14:31 ` Jeff Mahoney
2007-04-21 14:34 ` Jeff Mahoney
2007-04-21 15:26 ` Jeff Mahoney [this message]
2007-04-21 19:39 ` [PATCH] reiserfs: fix xattr root locking/refcount bug Andrew Morton
2007-04-22 10:28 ` Andrea Righi
2007-04-22 20:49 ` Jeff Mahoney
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=462A2D27.3060809@suse.com \
--to=jeffm@suse.com \
--cc=a.righi@cineca.it \
--cc=ak@suse.de \
--cc=akpm@linux-foundation.org \
--cc=edward@namesys.com \
--cc=linux-kernel@vger.kernel.org \
--cc=reiserfs-dev@namesys.com \
--cc=vs@namesys.com \
--cc=zam@clusterfs.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.