diff options
author | Yan, Zheng <zyan@redhat.com> | 2015-05-01 12:49:16 +0300 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2015-06-25 11:49:28 +0300 |
commit | 604d1b0245b97738cde4341944ad93edff4b2827 (patch) | |
tree | 05a75dfc1ddf4729405f9cb6ce2f405b8e47791e /fs/ceph/inode.c | |
parent | 860560904962d08fd38666207c910065fe53e074 (diff) | |
download | linux-604d1b0245b97738cde4341944ad93edff4b2827.tar.xz |
ceph: take snap_rwsem when accessing snap realm's cached_context
When ceph inode's i_head_snapc is NULL, __ceph_mark_dirty_caps()
accesses snap realm's cached_context. So we need take read lock
of snap_rwsem.
Signed-off-by: Yan, Zheng <zyan@redhat.com>
Diffstat (limited to 'fs/ceph/inode.c')
-rw-r--r-- | fs/ceph/inode.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 1a68c0e38a52..1c991df276c9 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1727,6 +1727,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) int mask = 0; int err = 0; int inode_dirty_flags = 0; + bool lock_snap_rwsem = false; if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; @@ -1742,6 +1743,18 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) spin_lock(&ci->i_ceph_lock); issued = __ceph_caps_issued(ci, NULL); + + if (!ci->i_head_snapc && + (issued & (CEPH_CAP_ANY_EXCL | CEPH_CAP_FILE_WR))) { + lock_snap_rwsem = true; + if (!down_read_trylock(&mdsc->snap_rwsem)) { + spin_unlock(&ci->i_ceph_lock); + down_read(&mdsc->snap_rwsem); + spin_lock(&ci->i_ceph_lock); + issued = __ceph_caps_issued(ci, NULL); + } + } + dout("setattr %p issued %s\n", inode, ceph_cap_string(issued)); if (ia_valid & ATTR_UID) { @@ -1890,6 +1903,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) release &= issued; spin_unlock(&ci->i_ceph_lock); + if (lock_snap_rwsem) + up_read(&mdsc->snap_rwsem); if (inode_dirty_flags) __mark_inode_dirty(inode, inode_dirty_flags); |