Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ceph: add a new flag to indicate whether parent is locked

struct ceph_mds_request has an r_locked_dir pointer, which is set to
indicate the parent inode and that its i_rwsem is locked. In some
critical places, we need to be able to indicate the parent inode to the
request handling code, even when its i_rwsem may not be locked.

Most of the code that operates on r_locked_dir doesn't require that the
i_rwsem be locked. We only really need it to handle manipulation of the
dcache. The rest (filling of the inode, updating dentry leases, etc.)
already has its own locking.

Add a new r_req_flags bit that indicates whether the parent is locked
when doing the request, and rename the pointer to "r_parent". For now,
all the places that set r_parent also set this flag, but that will
change in a later patch.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Yan, Zheng <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>

authored by

Jeff Layton and committed by
Ilya Dryomov
3dd69aab bc2de10d

+39 -28
+14 -7
fs/ceph/dir.c
··· 752 752 mask |= CEPH_CAP_XATTR_SHARED; 753 753 req->r_args.getattr.mask = cpu_to_le32(mask); 754 754 755 - req->r_locked_dir = dir; 755 + req->r_parent = dir; 756 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 756 757 err = ceph_mdsc_do_request(mdsc, NULL, req); 757 758 err = ceph_handle_snapdir(req, dentry, err); 758 759 dentry = ceph_finish_lookup(req, dentry, err); ··· 814 813 } 815 814 req->r_dentry = dget(dentry); 816 815 req->r_num_caps = 2; 817 - req->r_locked_dir = dir; 816 + req->r_parent = dir; 817 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 818 818 req->r_args.mknod.mode = cpu_to_le32(mode); 819 819 req->r_args.mknod.rdev = cpu_to_le32(rdev); 820 820 req->r_dentry_drop = CEPH_CAP_FILE_SHARED; ··· 866 864 ceph_mdsc_put_request(req); 867 865 goto out; 868 866 } 869 - req->r_locked_dir = dir; 867 + req->r_parent = dir; 868 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 870 869 req->r_dentry = dget(dentry); 871 870 req->r_num_caps = 2; 872 871 req->r_dentry_drop = CEPH_CAP_FILE_SHARED; ··· 916 913 917 914 req->r_dentry = dget(dentry); 918 915 req->r_num_caps = 2; 919 - req->r_locked_dir = dir; 916 + req->r_parent = dir; 917 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 920 918 req->r_args.mkdir.mode = cpu_to_le32(mode); 921 919 req->r_dentry_drop = CEPH_CAP_FILE_SHARED; 922 920 req->r_dentry_unless = CEPH_CAP_FILE_EXCL; ··· 961 957 req->r_dentry = dget(dentry); 962 958 req->r_num_caps = 2; 963 959 req->r_old_dentry = dget(old_dentry); 964 - req->r_locked_dir = dir; 960 + req->r_parent = dir; 961 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 965 962 req->r_dentry_drop = CEPH_CAP_FILE_SHARED; 966 963 req->r_dentry_unless = CEPH_CAP_FILE_EXCL; 967 964 /* release LINK_SHARED on source inode (mds will lock it) */ ··· 1028 1023 } 1029 1024 req->r_dentry = dget(dentry); 1030 1025 req->r_num_caps = 2; 1031 - req->r_locked_dir = dir; 1026 + req->r_parent = dir; 1027 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 1032 1028 req->r_dentry_drop = CEPH_CAP_FILE_SHARED; 1033 1029 req->r_dentry_unless = CEPH_CAP_FILE_EXCL; 1034 1030 req->r_inode_drop = drop_caps_for_unlink(inode); ··· 1072 1066 req->r_num_caps = 2; 1073 1067 req->r_old_dentry = dget(old_dentry); 1074 1068 req->r_old_dentry_dir = old_dir; 1075 - req->r_locked_dir = new_dir; 1069 + req->r_parent = new_dir; 1070 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 1076 1071 req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED; 1077 1072 req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL; 1078 1073 req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+2 -1
fs/ceph/export.c
··· 207 207 req->r_inode = d_inode(child); 208 208 ihold(d_inode(child)); 209 209 req->r_ino2 = ceph_vino(d_inode(parent)); 210 - req->r_locked_dir = d_inode(parent); 210 + req->r_parent = d_inode(parent); 211 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 211 212 req->r_num_caps = 2; 212 213 err = ceph_mdsc_do_request(mdsc, NULL, req); 213 214
+2 -1
fs/ceph/file.c
··· 379 379 mask |= CEPH_CAP_XATTR_SHARED; 380 380 req->r_args.open.mask = cpu_to_le32(mask); 381 381 382 - req->r_locked_dir = dir; /* caller holds dir->i_mutex */ 382 + req->r_parent = dir; 383 + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); 383 384 err = ceph_mdsc_do_request(mdsc, 384 385 (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, 385 386 req);
+7 -6
fs/ceph/inode.c
··· 1122 1122 1123 1123 if (!rinfo->head->is_target && !rinfo->head->is_dentry) { 1124 1124 dout("fill_trace reply is empty!\n"); 1125 - if (rinfo->head->result == 0 && req->r_locked_dir) 1125 + if (rinfo->head->result == 0 && req->r_parent) 1126 1126 ceph_invalidate_dir_request(req); 1127 1127 return 0; 1128 1128 } 1129 1129 1130 1130 if (rinfo->head->is_dentry) { 1131 - struct inode *dir = req->r_locked_dir; 1131 + struct inode *dir = req->r_parent; 1132 1132 1133 1133 if (dir) { 1134 1134 err = fill_inode(dir, NULL, ··· 1213 1213 * ignore null lease/binding on snapdir ENOENT, or else we 1214 1214 * will have trouble splicing in the virtual snapdir later 1215 1215 */ 1216 - if (rinfo->head->is_dentry && req->r_locked_dir && 1217 - !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags) && 1216 + if (rinfo->head->is_dentry && 1217 + !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags) && 1218 + test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags) && 1218 1219 (rinfo->head->is_target || strncmp(req->r_dentry->d_name.name, 1219 1220 fsc->mount_options->snapdir_name, 1220 1221 req->r_dentry->d_name.len))) { ··· 1224 1223 * mknod symlink mkdir : null -> new inode 1225 1224 * unlink : linked -> null 1226 1225 */ 1227 - struct inode *dir = req->r_locked_dir; 1226 + struct inode *dir = req->r_parent; 1228 1227 struct dentry *dn = req->r_dentry; 1229 1228 bool have_dir_cap, have_lease; 1230 1229 ··· 1322 1321 req->r_op == CEPH_MDS_OP_MKSNAP) && 1323 1322 !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) { 1324 1323 struct dentry *dn = req->r_dentry; 1325 - struct inode *dir = req->r_locked_dir; 1324 + struct inode *dir = req->r_parent; 1326 1325 1327 1326 /* fill out a snapdir LOOKUPSNAP dentry */ 1328 1327 BUG_ON(!dn);
+12 -12
fs/ceph/mds_client.c
··· 547 547 ceph_put_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); 548 548 iput(req->r_inode); 549 549 } 550 - if (req->r_locked_dir) 551 - ceph_put_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN); 550 + if (req->r_parent) 551 + ceph_put_cap_refs(ceph_inode(req->r_parent), CEPH_CAP_PIN); 552 552 iput(req->r_target_inode); 553 553 if (req->r_dentry) 554 554 dput(req->r_dentry); ··· 735 735 736 736 rcu_read_lock(); 737 737 parent = req->r_dentry->d_parent; 738 - dir = req->r_locked_dir ? : d_inode_rcu(parent); 738 + dir = req->r_parent ? : d_inode_rcu(parent); 739 739 740 740 if (!dir || dir->i_sb != mdsc->fsc->sb) { 741 741 /* not this fs or parent went negative */ ··· 1894 1894 int ret; 1895 1895 1896 1896 ret = set_request_path_attr(req->r_inode, req->r_dentry, 1897 - req->r_locked_dir, req->r_path1, req->r_ino1.ino, 1897 + req->r_parent, req->r_path1, req->r_ino1.ino, 1898 1898 &path1, &pathlen1, &ino1, &freepath1); 1899 1899 if (ret < 0) { 1900 1900 msg = ERR_PTR(ret); ··· 1956 1956 mds, req->r_inode_drop, req->r_inode_unless, 0); 1957 1957 if (req->r_dentry_drop) 1958 1958 releases += ceph_encode_dentry_release(&p, req->r_dentry, 1959 - req->r_locked_dir, mds, req->r_dentry_drop, 1959 + req->r_parent, mds, req->r_dentry_drop, 1960 1960 req->r_dentry_unless); 1961 1961 if (req->r_old_dentry_drop) 1962 1962 releases += ceph_encode_dentry_release(&p, req->r_old_dentry, ··· 2095 2095 rhead->oldest_client_tid = cpu_to_le64(__get_oldest_tid(mdsc)); 2096 2096 if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) 2097 2097 flags |= CEPH_MDS_FLAG_REPLAY; 2098 - if (req->r_locked_dir) 2098 + if (req->r_parent) 2099 2099 flags |= CEPH_MDS_FLAG_WANT_DENTRY; 2100 2100 rhead->flags = cpu_to_le32(flags); 2101 2101 rhead->num_fwd = req->r_num_fwd; 2102 2102 rhead->num_retry = req->r_attempts - 1; 2103 2103 rhead->ino = 0; 2104 2104 2105 - dout(" r_locked_dir = %p\n", req->r_locked_dir); 2105 + dout(" r_parent = %p\n", req->r_parent); 2106 2106 return 0; 2107 2107 } 2108 2108 ··· 2282 2282 2283 2283 dout("do_request on %p\n", req); 2284 2284 2285 - /* take CAP_PIN refs for r_inode, r_locked_dir, r_old_dentry */ 2285 + /* take CAP_PIN refs for r_inode, r_parent, r_old_dentry */ 2286 2286 if (req->r_inode) 2287 2287 ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); 2288 - if (req->r_locked_dir) 2289 - ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN); 2288 + if (req->r_parent) 2289 + ceph_get_cap_refs(ceph_inode(req->r_parent), CEPH_CAP_PIN); 2290 2290 if (req->r_old_dentry_dir) 2291 2291 ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir), 2292 2292 CEPH_CAP_PIN); ··· 2336 2336 set_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags); 2337 2337 mutex_unlock(&req->r_fill_mutex); 2338 2338 2339 - if (req->r_locked_dir && 2339 + if (req->r_parent && 2340 2340 (req->r_op & CEPH_MDS_OP_WRITE)) 2341 2341 ceph_invalidate_dir_request(req); 2342 2342 } else { ··· 2355 2355 */ 2356 2356 void ceph_invalidate_dir_request(struct ceph_mds_request *req) 2357 2357 { 2358 - struct inode *inode = req->r_locked_dir; 2358 + struct inode *inode = req->r_parent; 2359 2359 2360 2360 dout("invalidate_dir_request %p (complete, lease(s))\n", inode); 2361 2361
+2 -1
fs/ceph/mds_client.h
··· 202 202 char *r_path1, *r_path2; 203 203 struct ceph_vino r_ino1, r_ino2; 204 204 205 - struct inode *r_locked_dir; /* dir (if any) i_mutex locked by vfs */ 205 + struct inode *r_parent; /* parent dir inode */ 206 206 struct inode *r_target_inode; /* resulting inode */ 207 207 208 208 #define CEPH_MDS_R_DIRECT_IS_HASH (1) /* r_direct_hash is valid */ ··· 211 211 #define CEPH_MDS_R_GOT_SAFE (4) /* got a safe reply */ 212 212 #define CEPH_MDS_R_GOT_RESULT (5) /* got a result */ 213 213 #define CEPH_MDS_R_DID_PREPOPULATE (6) /* prepopulated readdir */ 214 + #define CEPH_MDS_R_PARENT_LOCKED (7) /* is r_parent->i_rwsem wlocked? */ 214 215 unsigned long r_req_flags; 215 216 216 217 struct mutex r_fill_mutex;