From: Josef Bacik <josef@redhat.com>
To: Ian Kent <raven@themaw.net>
Cc: Josef Bacik <josef@redhat.com>, linux-btrfs@vger.kernel.org
Subject: Re: [PATCH] Btrfs: fix dentry->d_parent abuses
Date: Thu, 28 Oct 2010 02:43:33 -0400 [thread overview]
Message-ID: <20101028064332.GA8899@dhcp231-156.rdu.redhat.com> (raw)
In-Reply-To: <1288237324.3151.17.camel@localhost>
On Thu, Oct 28, 2010 at 11:42:04AM +0800, Ian Kent wrote:
> On Wed, 2010-10-27 at 10:39 -0400, Josef Bacik wrote:
> > There are lots of places where we do dentry->d_parent->d_inode without holding
> > the dentry->d_lock. This could cause problems with rename. So instead use
> > dget_parent where we can, or in some cases we don't even need to use
> > dentry->d_parent->d_inode since we get the inode of the dir passed to us from
> > VFS. I tested this with xfstests and my no space tests and everything turned
> > out fine. Thanks,
> >
> > Signed-off-by: Josef Bacik <josef@redhat.com>
> > ---
> > fs/btrfs/file.c | 2 ++
> > fs/btrfs/inode.c | 48 ++++++++++++++++++++++++------------------------
> > fs/btrfs/ioctl.c | 11 +++++++++--
> > fs/btrfs/transaction.c | 5 ++++-
> > fs/btrfs/tree-log.c | 22 ++++++++++++++++++----
> > 5 files changed, 57 insertions(+), 31 deletions(-)
> >
> > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > index e354c33..6a4daa0 100644
> > --- a/fs/btrfs/file.c
> > +++ b/fs/btrfs/file.c
> > @@ -1047,8 +1047,10 @@ out:
> >
> > if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
> > trans = btrfs_start_transaction(root, 0);
>
> If btrfs_start_transaction() fails now the inode mutex will be held as
> well. I guess the resulting oops makes this irrelevant, ;)
>
> Looking through the dead end BUG_ON()s in the transaction code, and
> callers, one thing I've found difficult is working out how to recover
> from IS_ERR() returns from btrfs_start_transaction() in situations like
> this.
>
> Any chance of a patch to handle this to give me an example (well one
> case anyway) of how to do it?
>
Yup I can do that. Recovering from some of these errors is going to be tricky,
if you are going to work on that what I had in mind was doing alot of
static foo = 0;
foo++;
if (foo % 10000)
return (error where we used to BUG_ON());
so to be sure that all of a sudden returning an error doesn't cause an panic
farther up the callchain.
> > + mutex_lock(&inode->i_mutex);
> > ret = btrfs_log_dentry_safe(trans, root,
> > file->f_dentry);
> > + mutex_unlock(&inode->i_mutex);
> > if (ret == 0) {
> > ret = btrfs_sync_log(trans, root);
> > if (ret == 0)
> > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> > index 7146971..e77ee56 100644
> > --- a/fs/btrfs/inode.c
> > +++ b/fs/btrfs/inode.c
> > @@ -4144,6 +4144,7 @@ static int btrfs_dentry_delete(struct dentry *dentry)
> > if (btrfs_root_refs(&root->root_item) == 0)
> > return 1;
> > }
> > +
> > return 0;
> > }
> >
> > @@ -4627,12 +4628,12 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
> > }
> >
> > static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
> > - struct dentry *dentry, struct inode *inode,
> > - int backref, u64 index)
> > + struct inode *dir, struct dentry *dentry,
> > + struct inode *inode, int backref, u64 index)
> > {
> > - int err = btrfs_add_link(trans, dentry->d_parent->d_inode,
> > - inode, dentry->d_name.name,
> > - dentry->d_name.len, backref, index);
> > + int err = btrfs_add_link(trans, dir, inode,
> > + dentry->d_name.name, dentry->d_name.len,
> > + backref, index);
> > if (!err) {
> > d_instantiate(dentry, inode);
> > return 0;
> > @@ -4673,8 +4674,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
> > btrfs_set_trans_block_group(trans, dir);
> >
> > inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
> > - dentry->d_name.len,
> > - dentry->d_parent->d_inode->i_ino, objectid,
> > + dentry->d_name.len, dir->i_ino, objectid,
> > BTRFS_I(dir)->block_group, mode, &index);
> > err = PTR_ERR(inode);
> > if (IS_ERR(inode))
> > @@ -4687,7 +4687,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
> > }
> >
> > btrfs_set_trans_block_group(trans, inode);
> > - err = btrfs_add_nondir(trans, dentry, inode, 0, index);
> > + err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
> > if (err)
> > drop_inode = 1;
> > else {
> > @@ -4735,10 +4735,8 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
> > btrfs_set_trans_block_group(trans, dir);
> >
> > inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
> > - dentry->d_name.len,
> > - dentry->d_parent->d_inode->i_ino,
> > - objectid, BTRFS_I(dir)->block_group, mode,
> > - &index);
> > + dentry->d_name.len, dir->i_ino, objectid,
> > + BTRFS_I(dir)->block_group, mode, &index);
> > err = PTR_ERR(inode);
> > if (IS_ERR(inode))
> > goto out_unlock;
> > @@ -4750,7 +4748,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
> > }
> >
> > btrfs_set_trans_block_group(trans, inode);
> > - err = btrfs_add_nondir(trans, dentry, inode, 0, index);
> > + err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
> > if (err)
> > drop_inode = 1;
> > else {
> > @@ -4810,15 +4808,17 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
> > btrfs_set_trans_block_group(trans, dir);
> > atomic_inc(&inode->i_count);
> >
> > - err = btrfs_add_nondir(trans, dentry, inode, 1, index);
> > + err = btrfs_add_nondir(trans, dir, dentry, inode, 1, index);
> >
> > if (err) {
> > drop_inode = 1;
> > } else {
> > + struct dentry *parent = dget_parent(dentry);
> > btrfs_update_inode_block_group(trans, dir);
> > err = btrfs_update_inode(trans, root, inode);
> > BUG_ON(err);
> > - btrfs_log_new_name(trans, inode, NULL, dentry->d_parent);
> > + btrfs_log_new_name(trans, inode, NULL, parent);
> > + dput(parent);
> > }
> >
> > nr = trans->blocks_used;
> > @@ -4858,8 +4858,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
> > btrfs_set_trans_block_group(trans, dir);
> >
> > inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
> > - dentry->d_name.len,
> > - dentry->d_parent->d_inode->i_ino, objectid,
> > + dentry->d_name.len, dir->i_ino, objectid,
> > BTRFS_I(dir)->block_group, S_IFDIR | mode,
> > &index);
> > if (IS_ERR(inode)) {
> > @@ -4882,9 +4881,8 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
> > if (err)
> > goto out_fail;
> >
> > - err = btrfs_add_link(trans, dentry->d_parent->d_inode,
> > - inode, dentry->d_name.name,
> > - dentry->d_name.len, 0, index);
> > + err = btrfs_add_link(trans, dir, inode, dentry->d_name.name,
> > + dentry->d_name.len, 0, index);
> > if (err)
> > goto out_fail;
> >
> > @@ -6613,8 +6611,11 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
> > BUG_ON(ret);
> >
> > if (old_inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
> > + struct dentry *parent = dget_parent(new_dentry);
> > +
> > btrfs_log_new_name(trans, old_inode, old_dir,
> > - new_dentry->d_parent);
> > + parent);
> > + dput(parent);
> > btrfs_end_log_trans(root);
> > }
> > out_fail:
> > @@ -6764,8 +6765,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
> > btrfs_set_trans_block_group(trans, dir);
> >
> > inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name,
> > - dentry->d_name.len,
> > - dentry->d_parent->d_inode->i_ino, objectid,
> > + dentry->d_name.len, dir->i_ino, objectid,
> > BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO,
> > &index);
> > err = PTR_ERR(inode);
> > @@ -6779,7 +6779,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
> > }
> >
> > btrfs_set_trans_block_group(trans, inode);
> > - err = btrfs_add_nondir(trans, dentry, inode, 0, index);
> > + err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
> > if (err)
> > drop_inode = 1;
> > else {
> > diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> > index e264072..396ccd1 100644
> > --- a/fs/btrfs/ioctl.c
> > +++ b/fs/btrfs/ioctl.c
> > @@ -232,13 +232,17 @@ static noinline int create_subvol(struct btrfs_root *root,
> > struct btrfs_inode_item *inode_item;
> > struct extent_buffer *leaf;
> > struct btrfs_root *new_root;
> > - struct inode *dir = dentry->d_parent->d_inode;
> > + struct dentry *parent = dget_parent(dentry);
> > + struct inode *dir;
> > int ret;
> > int err;
> > u64 objectid;
> > u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
> > u64 index = 0;
> >
> > + dir = parent->d_inode;
> > + dput(parent);
>
> I get that parent is, well, the parent so the child were using will hold
> a reference to it and so the dput() should be safe. But, since we have
> the reference why not hold it while we use the inode to make certain the
> inode cannot go away?
>
Yeah good point, I wasn't entirely sure how to deal with these cases so I just
made something up. I'm happy to have a more solid alternative. Thanks for the
review, I'll fix all this up at a more reasonable hour,
Josef
next prev parent reply other threads:[~2010-10-28 6:43 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-27 14:39 [PATCH] Btrfs: fix dentry->d_parent abuses Josef Bacik
2010-10-27 14:53 ` system crash at mounting of btrfs Erik Hoppe
2010-10-28 3:42 ` [PATCH] Btrfs: fix dentry->d_parent abuses Ian Kent
2010-10-28 6:43 ` Josef Bacik [this message]
2010-10-28 10:08 ` Ian Kent
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=20101028064332.GA8899@dhcp231-156.rdu.redhat.com \
--to=josef@redhat.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=raven@themaw.net \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).