diff options
author | Sage Weil <sage@newdream.net> | 2010-08-26 16:12:01 -0700 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2010-09-11 10:52:47 -0700 |
commit | ca04d9c3ec721e474f00992efc1b1afb625507f5 (patch) | |
tree | 9dfe95fe2a08ff008888a754db10f31ac04fbea4 /fs | |
parent | 2bfc96a127bc1cc94d26bfaa40159966064f9c8c (diff) |
ceph: fix null pointer deref on anon root dentry release
When we release a root dentry, particularly after a splice, the parent
(actually our) inode was evaluating to NULL and was getting dereferenced
by ceph_snap(). This is reproduced by something as simple as
mount -t ceph monhost:/a/b mnt
mount -t ceph monhost:/a mnt2
ls mnt2
A splice_dentry() would kill the old 'b' inode's root dentry, and we'd
crash while releasing it.
Fix by checking for both the ROOT and NULL cases explicitly. We only need
to invalidate the parent dir when we have a correct parent to invalidate.
Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ceph/dir.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 6e4f43ff23e..a1986eb5204 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1021,11 +1021,15 @@ out_touch: static void ceph_dentry_release(struct dentry *dentry) { struct ceph_dentry_info *di = ceph_dentry(dentry); - struct inode *parent_inode = dentry->d_parent->d_inode; - u64 snapid = ceph_snap(parent_inode); + struct inode *parent_inode = NULL; + u64 snapid = CEPH_NOSNAP; + if (!IS_ROOT(dentry)) { + parent_inode = dentry->d_parent->d_inode; + if (parent_inode) + snapid = ceph_snap(parent_inode); + } dout("dentry_release %p parent %p\n", dentry, parent_inode); - if (parent_inode && snapid != CEPH_SNAPDIR) { struct ceph_inode_info *ci = ceph_inode(parent_inode); |