All of lore.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: jlayton@kernel.org
Cc: linux-fsdevel@vger.kernel.org, ceph-devel@vger.kernel.org
Subject: [deadlock or dead code] ceph_encode_dentry_release() misuse of dget()
Date: Thu, 16 Nov 2023 08:19:19 +0000	[thread overview]
Message-ID: <20231116081919.GZ1957730@ZenIV> (raw)

This
        spin_lock(&dentry->d_lock);
        if (di->lease_session && di->lease_session->s_mds == mds)
                force = 1;
        if (!dir) {
                parent = dget(dentry->d_parent);
                dir = d_inode(parent);
        }
        spin_unlock(&dentry->d_lock);
has a problem if we ever get called with dir == NULL.

The thing is, dget(dentry->d_parent) will spin if dentry->d_parent->d_lock
is held.  IOW, the whole thing is an equivalent of
	spin_lock(&dentry->d_lock);
	spin_lock(&dentry->d_parent->d_lock);
which takes them in the wrong order.

Said that, I'm not sure it ever gets called with dir == NULL;
we have two callers -
        if (req->r_dentry_drop) {
                ret = ceph_encode_dentry_release(&p, req->r_dentry,
                                req->r_parent, mds, req->r_dentry_drop,
                                req->r_dentry_unless);
                if (ret < 0)
                        goto out_err;
                releases += ret;
        }
and
        if (req->r_old_dentry_drop) {
                ret = ceph_encode_dentry_release(&p, req->r_old_dentry,
                                req->r_old_dentry_dir, mds,
                                req->r_old_dentry_drop,
                                req->r_old_dentry_unless);
                if (ret < 0)
                        goto out_err;
                releases += ret;
        }
Now, ->r_dentry_drop is set in ceph_mknod(), ceph_symlink(), ceph_mkdir(),
ceph_link(), ceph_unlink(), all with
        req->r_parent = dir;
        ihold(dir);
ceph_rename(), with
        req->r_parent = new_dir;
        ihold(new_dir);
and ceph_atomic_open(), with
        req->r_parent = dir;
        if (req->r_op == CEPH_MDS_OP_CREATE)
                req->r_mnt_idmap = mnt_idmap_get(idmap);
        ihold(dir);
All of that will oops if ->r_parent set to NULL.
->r_old_dentry_drop() is set in ceph_rename(), with
        struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(old_dir->i_sb);
	...
        req->r_old_dentry_dir = old_dir;
which also can't manage to leave ->r_old_dentry_dir set to NULL.

Am I missing something subtle here?  Looks like that dget() is never
reached...

             reply	other threads:[~2023-11-16  8:19 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-16  8:19 Al Viro [this message]
2023-11-16 12:50 ` [deadlock or dead code] ceph_encode_dentry_release() misuse of dget() Jeff Layton
2023-11-16 16:28   ` Al Viro
2023-11-16 16:50     ` Jeff Layton
2023-11-17  0:15       ` Xiubo Li

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=20231116081919.GZ1957730@ZenIV \
    --to=viro@zeniv.linux.org.uk \
    --cc=ceph-devel@vger.kernel.org \
    --cc=jlayton@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    /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.