hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/ceph/dir.c
....@@ -29,12 +29,16 @@
2929
3030 const struct dentry_operations ceph_dentry_ops;
3131
32
+static bool __dentry_lease_is_valid(struct ceph_dentry_info *di);
33
+static int __dir_lease_try_check(const struct dentry *dentry);
34
+
3235 /*
3336 * Initialize ceph dentry state.
3437 */
3538 static int ceph_d_init(struct dentry *dentry)
3639 {
3740 struct ceph_dentry_info *di;
41
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dentry->d_sb);
3842
3943 di = kmem_cache_zalloc(ceph_dentry_cachep, GFP_KERNEL);
4044 if (!di)
....@@ -44,7 +48,10 @@
4448 di->lease_session = NULL;
4549 di->time = jiffies;
4650 dentry->d_fsdata = di;
47
- ceph_dentry_lru_add(dentry);
51
+ INIT_LIST_HEAD(&di->lease_list);
52
+
53
+ atomic64_inc(&mdsc->metric.total_dentries);
54
+
4855 return 0;
4956 }
5057
....@@ -241,6 +248,7 @@
241248 goto out;
242249 }
243250 if (fpos_cmp(ctx->pos, di->offset) <= 0) {
251
+ __ceph_dentry_dir_lease_touch(di);
244252 emit_dentry = true;
245253 }
246254 spin_unlock(&dentry->d_lock);
....@@ -250,9 +258,7 @@
250258 dentry, dentry, d_inode(dentry));
251259 ctx->pos = di->offset;
252260 if (!dir_emit(ctx, dentry->d_name.name,
253
- dentry->d_name.len,
254
- ceph_translate_ino(dentry->d_sb,
255
- d_inode(dentry)->i_ino),
261
+ dentry->d_name.len, ceph_present_inode(d_inode(dentry)),
256262 d_inode(dentry)->i_mode >> 12)) {
257263 dput(dentry);
258264 err = 0;
....@@ -315,30 +321,37 @@
315321 /* always start with . and .. */
316322 if (ctx->pos == 0) {
317323 dout("readdir off 0 -> '.'\n");
318
- if (!dir_emit(ctx, ".", 1,
319
- ceph_translate_ino(inode->i_sb, inode->i_ino),
324
+ if (!dir_emit(ctx, ".", 1, ceph_present_inode(inode),
320325 inode->i_mode >> 12))
321326 return 0;
322327 ctx->pos = 1;
323328 }
324329 if (ctx->pos == 1) {
325
- ino_t ino = parent_ino(file->f_path.dentry);
330
+ u64 ino;
331
+ struct dentry *dentry = file->f_path.dentry;
332
+
333
+ spin_lock(&dentry->d_lock);
334
+ ino = ceph_present_inode(dentry->d_parent->d_inode);
335
+ spin_unlock(&dentry->d_lock);
336
+
326337 dout("readdir off 1 -> '..'\n");
327
- if (!dir_emit(ctx, "..", 2,
328
- ceph_translate_ino(inode->i_sb, ino),
329
- inode->i_mode >> 12))
338
+ if (!dir_emit(ctx, "..", 2, ino, inode->i_mode >> 12))
330339 return 0;
331340 ctx->pos = 2;
332341 }
333342
334
- /* can we use the dcache? */
335343 spin_lock(&ci->i_ceph_lock);
344
+ /* request Fx cap. if have Fx, we don't need to release Fs cap
345
+ * for later create/unlink. */
346
+ __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_WR);
347
+ /* can we use the dcache? */
336348 if (ceph_test_mount_opt(fsc, DCACHE) &&
337349 !ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
338350 ceph_snap(inode) != CEPH_SNAPDIR &&
339351 __ceph_dir_is_complete_ordered(ci) &&
340
- __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
352
+ __ceph_caps_issued_mask_metric(ci, CEPH_CAP_FILE_SHARED, 1)) {
341353 int shared_gen = atomic_read(&ci->i_shared_gen);
354
+
342355 spin_unlock(&ci->i_ceph_lock);
343356 err = __dcache_readdir(file, ctx, shared_gen);
344357 if (err != -EAGAIN)
....@@ -465,8 +478,11 @@
465478 2 : (fpos_off(rde->offset) + 1);
466479 err = note_last_dentry(dfi, rde->name, rde->name_len,
467480 next_offset);
468
- if (err)
481
+ if (err) {
482
+ ceph_mdsc_put_request(dfi->last_readdir);
483
+ dfi->last_readdir = NULL;
469484 return err;
485
+ }
470486 } else if (req->r_reply_info.dir_end) {
471487 dfi->next_offset = 2;
472488 /* keep last name */
....@@ -494,9 +510,6 @@
494510 }
495511 for (; i < rinfo->dir_nr; i++) {
496512 struct ceph_mds_reply_dir_entry *rde = rinfo->dir_entries + i;
497
- struct ceph_vino vino;
498
- ino_t ino;
499
- u32 ftype;
500513
501514 BUG_ON(rde->offset < ctx->pos);
502515
....@@ -506,13 +519,16 @@
506519 rde->name_len, rde->name, &rde->inode.in);
507520
508521 BUG_ON(!rde->inode.in);
509
- ftype = le32_to_cpu(rde->inode.in->mode) >> 12;
510
- vino.ino = le64_to_cpu(rde->inode.in->ino);
511
- vino.snap = le64_to_cpu(rde->inode.in->snapid);
512
- ino = ceph_vino_to_ino(vino);
513522
514523 if (!dir_emit(ctx, rde->name, rde->name_len,
515
- ceph_translate_ino(inode->i_sb, ino), ftype)) {
524
+ ceph_present_ino(inode->i_sb, le64_to_cpu(rde->inode.in->ino)),
525
+ le32_to_cpu(rde->inode.in->mode) >> 12)) {
526
+ /*
527
+ * NOTE: Here no need to put the 'dfi->last_readdir',
528
+ * because when dir_emit stops us it's most likely
529
+ * doesn't have enough memory, etc. So for next readdir
530
+ * it will continue.
531
+ */
516532 dout("filldir stopping us...\n");
517533 return 0;
518534 }
....@@ -730,7 +746,7 @@
730746 unsigned int flags)
731747 {
732748 struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
733
- struct ceph_mds_client *mdsc = fsc->mdsc;
749
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
734750 struct ceph_mds_request *req;
735751 int op;
736752 int mask;
....@@ -748,14 +764,15 @@
748764 struct ceph_dentry_info *di = ceph_dentry(dentry);
749765
750766 spin_lock(&ci->i_ceph_lock);
751
- dout(" dir %p flags are %d\n", dir, ci->i_ceph_flags);
767
+ dout(" dir %p flags are 0x%lx\n", dir, ci->i_ceph_flags);
752768 if (strncmp(dentry->d_name.name,
753769 fsc->mount_options->snapdir_name,
754770 dentry->d_name.len) &&
755771 !is_root_ceph_dentry(dir, dentry) &&
756772 ceph_test_mount_opt(fsc, DCACHE) &&
757773 __ceph_dir_is_complete(ci) &&
758
- (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
774
+ __ceph_caps_issued_mask_metric(ci, CEPH_CAP_FILE_SHARED, 1)) {
775
+ __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
759776 spin_unlock(&ci->i_ceph_lock);
760777 dout(" dir %p complete, -ENOENT\n", dir);
761778 d_add(dentry, NULL);
....@@ -818,10 +835,9 @@
818835 static int ceph_mknod(struct inode *dir, struct dentry *dentry,
819836 umode_t mode, dev_t rdev)
820837 {
821
- struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
822
- struct ceph_mds_client *mdsc = fsc->mdsc;
838
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
823839 struct ceph_mds_request *req;
824
- struct ceph_acls_info acls = {};
840
+ struct ceph_acl_sec_ctx as_ctx = {};
825841 int err;
826842
827843 if (ceph_snap(dir) != CEPH_NOSNAP)
....@@ -832,7 +848,10 @@
832848 goto out;
833849 }
834850
835
- err = ceph_pre_init_acls(dir, &mode, &acls);
851
+ err = ceph_pre_init_acls(dir, &mode, &as_ctx);
852
+ if (err < 0)
853
+ goto out;
854
+ err = ceph_security_init_secctx(dentry, mode, &as_ctx);
836855 if (err < 0)
837856 goto out;
838857
....@@ -851,9 +870,9 @@
851870 req->r_args.mknod.rdev = cpu_to_le32(rdev);
852871 req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL;
853872 req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
854
- if (acls.pagelist) {
855
- req->r_pagelist = acls.pagelist;
856
- acls.pagelist = NULL;
873
+ if (as_ctx.pagelist) {
874
+ req->r_pagelist = as_ctx.pagelist;
875
+ as_ctx.pagelist = NULL;
857876 }
858877 err = ceph_mdsc_do_request(mdsc, dir, req);
859878 if (!err && !req->r_reply_info.head->is_dentry)
....@@ -861,10 +880,10 @@
861880 ceph_mdsc_put_request(req);
862881 out:
863882 if (!err)
864
- ceph_init_inode_acls(d_inode(dentry), &acls);
883
+ ceph_init_inode_acls(d_inode(dentry), &as_ctx);
865884 else
866885 d_drop(dentry);
867
- ceph_release_acls_info(&acls);
886
+ ceph_release_acl_sec_ctx(&as_ctx);
868887 return err;
869888 }
870889
....@@ -877,9 +896,9 @@
877896 static int ceph_symlink(struct inode *dir, struct dentry *dentry,
878897 const char *dest)
879898 {
880
- struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
881
- struct ceph_mds_client *mdsc = fsc->mdsc;
899
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
882900 struct ceph_mds_request *req;
901
+ struct ceph_acl_sec_ctx as_ctx = {};
883902 int err;
884903
885904 if (ceph_snap(dir) != CEPH_NOSNAP)
....@@ -889,6 +908,10 @@
889908 err = -EDQUOT;
890909 goto out;
891910 }
911
+
912
+ err = ceph_security_init_secctx(dentry, S_IFLNK | 0777, &as_ctx);
913
+ if (err < 0)
914
+ goto out;
892915
893916 dout("symlink in dir %p dentry %p to '%s'\n", dir, dentry, dest);
894917 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SYMLINK, USE_AUTH_MDS);
....@@ -908,6 +931,10 @@
908931 req->r_num_caps = 2;
909932 req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL;
910933 req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
934
+ if (as_ctx.pagelist) {
935
+ req->r_pagelist = as_ctx.pagelist;
936
+ as_ctx.pagelist = NULL;
937
+ }
911938 err = ceph_mdsc_do_request(mdsc, dir, req);
912939 if (!err && !req->r_reply_info.head->is_dentry)
913940 err = ceph_handle_notrace_create(dir, dentry);
....@@ -915,15 +942,15 @@
915942 out:
916943 if (err)
917944 d_drop(dentry);
945
+ ceph_release_acl_sec_ctx(&as_ctx);
918946 return err;
919947 }
920948
921949 static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
922950 {
923
- struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
924
- struct ceph_mds_client *mdsc = fsc->mdsc;
951
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
925952 struct ceph_mds_request *req;
926
- struct ceph_acls_info acls = {};
953
+ struct ceph_acl_sec_ctx as_ctx = {};
927954 int err = -EROFS;
928955 int op;
929956
....@@ -946,7 +973,10 @@
946973 }
947974
948975 mode |= S_IFDIR;
949
- err = ceph_pre_init_acls(dir, &mode, &acls);
976
+ err = ceph_pre_init_acls(dir, &mode, &as_ctx);
977
+ if (err < 0)
978
+ goto out;
979
+ err = ceph_security_init_secctx(dentry, mode, &as_ctx);
950980 if (err < 0)
951981 goto out;
952982
....@@ -963,9 +993,9 @@
963993 req->r_args.mkdir.mode = cpu_to_le32(mode);
964994 req->r_dentry_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_AUTH_EXCL;
965995 req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
966
- if (acls.pagelist) {
967
- req->r_pagelist = acls.pagelist;
968
- acls.pagelist = NULL;
996
+ if (as_ctx.pagelist) {
997
+ req->r_pagelist = as_ctx.pagelist;
998
+ as_ctx.pagelist = NULL;
969999 }
9701000 err = ceph_mdsc_do_request(mdsc, dir, req);
9711001 if (!err &&
....@@ -975,18 +1005,17 @@
9751005 ceph_mdsc_put_request(req);
9761006 out:
9771007 if (!err)
978
- ceph_init_inode_acls(d_inode(dentry), &acls);
1008
+ ceph_init_inode_acls(d_inode(dentry), &as_ctx);
9791009 else
9801010 d_drop(dentry);
981
- ceph_release_acls_info(&acls);
1011
+ ceph_release_acl_sec_ctx(&as_ctx);
9821012 return err;
9831013 }
9841014
9851015 static int ceph_link(struct dentry *old_dentry, struct inode *dir,
9861016 struct dentry *dentry)
9871017 {
988
- struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
989
- struct ceph_mds_client *mdsc = fsc->mdsc;
1018
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
9901019 struct ceph_mds_request *req;
9911020 int err;
9921021
....@@ -1020,6 +1049,78 @@
10201049 return err;
10211050 }
10221051
1052
+static void ceph_async_unlink_cb(struct ceph_mds_client *mdsc,
1053
+ struct ceph_mds_request *req)
1054
+{
1055
+ int result = req->r_err ? req->r_err :
1056
+ le32_to_cpu(req->r_reply_info.head->result);
1057
+
1058
+ if (result == -EJUKEBOX)
1059
+ goto out;
1060
+
1061
+ /* If op failed, mark everyone involved for errors */
1062
+ if (result) {
1063
+ int pathlen = 0;
1064
+ u64 base = 0;
1065
+ char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
1066
+ &base, 0);
1067
+
1068
+ /* mark error on parent + clear complete */
1069
+ mapping_set_error(req->r_parent->i_mapping, result);
1070
+ ceph_dir_clear_complete(req->r_parent);
1071
+
1072
+ /* drop the dentry -- we don't know its status */
1073
+ if (!d_unhashed(req->r_dentry))
1074
+ d_drop(req->r_dentry);
1075
+
1076
+ /* mark inode itself for an error (since metadata is bogus) */
1077
+ mapping_set_error(req->r_old_inode->i_mapping, result);
1078
+
1079
+ pr_warn("ceph: async unlink failure path=(%llx)%s result=%d!\n",
1080
+ base, IS_ERR(path) ? "<<bad>>" : path, result);
1081
+ ceph_mdsc_free_path(path, pathlen);
1082
+ }
1083
+out:
1084
+ iput(req->r_old_inode);
1085
+ ceph_mdsc_release_dir_caps(req);
1086
+}
1087
+
1088
+static int get_caps_for_async_unlink(struct inode *dir, struct dentry *dentry)
1089
+{
1090
+ struct ceph_inode_info *ci = ceph_inode(dir);
1091
+ struct ceph_dentry_info *di;
1092
+ int got = 0, want = CEPH_CAP_FILE_EXCL | CEPH_CAP_DIR_UNLINK;
1093
+
1094
+ spin_lock(&ci->i_ceph_lock);
1095
+ if ((__ceph_caps_issued(ci, NULL) & want) == want) {
1096
+ ceph_take_cap_refs(ci, want, false);
1097
+ got = want;
1098
+ }
1099
+ spin_unlock(&ci->i_ceph_lock);
1100
+
1101
+ /* If we didn't get anything, return 0 */
1102
+ if (!got)
1103
+ return 0;
1104
+
1105
+ spin_lock(&dentry->d_lock);
1106
+ di = ceph_dentry(dentry);
1107
+ /*
1108
+ * - We are holding Fx, which implies Fs caps.
1109
+ * - Only support async unlink for primary linkage
1110
+ */
1111
+ if (atomic_read(&ci->i_shared_gen) != di->lease_shared_gen ||
1112
+ !(di->flags & CEPH_DENTRY_PRIMARY_LINK))
1113
+ want = 0;
1114
+ spin_unlock(&dentry->d_lock);
1115
+
1116
+ /* Do we still want what we've got? */
1117
+ if (want == got)
1118
+ return got;
1119
+
1120
+ ceph_put_cap_refs(ci, got);
1121
+ return 0;
1122
+}
1123
+
10231124 /*
10241125 * rmdir and unlink are differ only by the metadata op code
10251126 */
....@@ -1029,6 +1130,7 @@
10291130 struct ceph_mds_client *mdsc = fsc->mdsc;
10301131 struct inode *inode = d_inode(dentry);
10311132 struct ceph_mds_request *req;
1133
+ bool try_async = ceph_test_mount_opt(fsc, ASYNC_DIROPS);
10321134 int err = -EROFS;
10331135 int op;
10341136
....@@ -1043,6 +1145,7 @@
10431145 CEPH_MDS_OP_RMDIR : CEPH_MDS_OP_UNLINK;
10441146 } else
10451147 goto out;
1148
+retry:
10461149 req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
10471150 if (IS_ERR(req)) {
10481151 err = PTR_ERR(req);
....@@ -1051,13 +1154,39 @@
10511154 req->r_dentry = dget(dentry);
10521155 req->r_num_caps = 2;
10531156 req->r_parent = dir;
1054
- set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
10551157 req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
10561158 req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
10571159 req->r_inode_drop = ceph_drop_caps_for_unlink(inode);
1058
- err = ceph_mdsc_do_request(mdsc, dir, req);
1059
- if (!err && !req->r_reply_info.head->is_dentry)
1060
- d_delete(dentry);
1160
+
1161
+ if (try_async && op == CEPH_MDS_OP_UNLINK &&
1162
+ (req->r_dir_caps = get_caps_for_async_unlink(dir, dentry))) {
1163
+ dout("async unlink on %llu/%.*s caps=%s", ceph_ino(dir),
1164
+ dentry->d_name.len, dentry->d_name.name,
1165
+ ceph_cap_string(req->r_dir_caps));
1166
+ set_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags);
1167
+ req->r_callback = ceph_async_unlink_cb;
1168
+ req->r_old_inode = d_inode(dentry);
1169
+ ihold(req->r_old_inode);
1170
+ err = ceph_mdsc_submit_request(mdsc, dir, req);
1171
+ if (!err) {
1172
+ /*
1173
+ * We have enough caps, so we assume that the unlink
1174
+ * will succeed. Fix up the target inode and dcache.
1175
+ */
1176
+ drop_nlink(inode);
1177
+ d_delete(dentry);
1178
+ } else if (err == -EJUKEBOX) {
1179
+ try_async = false;
1180
+ ceph_mdsc_put_request(req);
1181
+ goto retry;
1182
+ }
1183
+ } else {
1184
+ set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
1185
+ err = ceph_mdsc_do_request(mdsc, dir, req);
1186
+ if (!err && !req->r_reply_info.head->is_dentry)
1187
+ d_delete(dentry);
1188
+ }
1189
+
10611190 ceph_mdsc_put_request(req);
10621191 out:
10631192 return err;
....@@ -1067,8 +1196,7 @@
10671196 struct inode *new_dir, struct dentry *new_dentry,
10681197 unsigned int flags)
10691198 {
1070
- struct ceph_fs_client *fsc = ceph_sb_to_client(old_dir->i_sb);
1071
- struct ceph_mds_client *mdsc = fsc->mdsc;
1199
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(old_dir->i_sb);
10721200 struct ceph_mds_request *req;
10731201 int op = CEPH_MDS_OP_RENAME;
10741202 int err;
....@@ -1083,11 +1211,12 @@
10831211 op = CEPH_MDS_OP_RENAMESNAP;
10841212 else
10851213 return -EROFS;
1214
+ } else if (old_dir != new_dir) {
1215
+ err = ceph_quota_check_rename(mdsc, d_inode(old_dentry),
1216
+ new_dir);
1217
+ if (err)
1218
+ return err;
10861219 }
1087
- /* don't allow cross-quota renames */
1088
- if ((old_dir != new_dir) &&
1089
- (!ceph_quota_is_same_realm(old_dir, new_dir)))
1090
- return -EXDEV;
10911220
10921221 dout("rename dir %p dentry %p to dir %p dentry %p\n",
10931222 old_dir, old_dentry, new_dir, new_dentry);
....@@ -1125,13 +1254,278 @@
11251254 }
11261255
11271256 /*
1257
+ * Move dentry to tail of mdsc->dentry_leases list when lease is updated.
1258
+ * Leases at front of the list will expire first. (Assume all leases have
1259
+ * similar duration)
1260
+ *
1261
+ * Called under dentry->d_lock.
1262
+ */
1263
+void __ceph_dentry_lease_touch(struct ceph_dentry_info *di)
1264
+{
1265
+ struct dentry *dn = di->dentry;
1266
+ struct ceph_mds_client *mdsc;
1267
+
1268
+ dout("dentry_lease_touch %p %p '%pd'\n", di, dn, dn);
1269
+
1270
+ di->flags |= CEPH_DENTRY_LEASE_LIST;
1271
+ if (di->flags & CEPH_DENTRY_SHRINK_LIST) {
1272
+ di->flags |= CEPH_DENTRY_REFERENCED;
1273
+ return;
1274
+ }
1275
+
1276
+ mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
1277
+ spin_lock(&mdsc->dentry_list_lock);
1278
+ list_move_tail(&di->lease_list, &mdsc->dentry_leases);
1279
+ spin_unlock(&mdsc->dentry_list_lock);
1280
+}
1281
+
1282
+static void __dentry_dir_lease_touch(struct ceph_mds_client* mdsc,
1283
+ struct ceph_dentry_info *di)
1284
+{
1285
+ di->flags &= ~(CEPH_DENTRY_LEASE_LIST | CEPH_DENTRY_REFERENCED);
1286
+ di->lease_gen = 0;
1287
+ di->time = jiffies;
1288
+ list_move_tail(&di->lease_list, &mdsc->dentry_dir_leases);
1289
+}
1290
+
1291
+/*
1292
+ * When dir lease is used, add dentry to tail of mdsc->dentry_dir_leases
1293
+ * list if it's not in the list, otherwise set 'referenced' flag.
1294
+ *
1295
+ * Called under dentry->d_lock.
1296
+ */
1297
+void __ceph_dentry_dir_lease_touch(struct ceph_dentry_info *di)
1298
+{
1299
+ struct dentry *dn = di->dentry;
1300
+ struct ceph_mds_client *mdsc;
1301
+
1302
+ dout("dentry_dir_lease_touch %p %p '%pd' (offset 0x%llx)\n",
1303
+ di, dn, dn, di->offset);
1304
+
1305
+ if (!list_empty(&di->lease_list)) {
1306
+ if (di->flags & CEPH_DENTRY_LEASE_LIST) {
1307
+ /* don't remove dentry from dentry lease list
1308
+ * if its lease is valid */
1309
+ if (__dentry_lease_is_valid(di))
1310
+ return;
1311
+ } else {
1312
+ di->flags |= CEPH_DENTRY_REFERENCED;
1313
+ return;
1314
+ }
1315
+ }
1316
+
1317
+ if (di->flags & CEPH_DENTRY_SHRINK_LIST) {
1318
+ di->flags |= CEPH_DENTRY_REFERENCED;
1319
+ di->flags &= ~CEPH_DENTRY_LEASE_LIST;
1320
+ return;
1321
+ }
1322
+
1323
+ mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
1324
+ spin_lock(&mdsc->dentry_list_lock);
1325
+ __dentry_dir_lease_touch(mdsc, di),
1326
+ spin_unlock(&mdsc->dentry_list_lock);
1327
+}
1328
+
1329
+static void __dentry_lease_unlist(struct ceph_dentry_info *di)
1330
+{
1331
+ struct ceph_mds_client *mdsc;
1332
+ if (di->flags & CEPH_DENTRY_SHRINK_LIST)
1333
+ return;
1334
+ if (list_empty(&di->lease_list))
1335
+ return;
1336
+
1337
+ mdsc = ceph_sb_to_client(di->dentry->d_sb)->mdsc;
1338
+ spin_lock(&mdsc->dentry_list_lock);
1339
+ list_del_init(&di->lease_list);
1340
+ spin_unlock(&mdsc->dentry_list_lock);
1341
+}
1342
+
1343
+enum {
1344
+ KEEP = 0,
1345
+ DELETE = 1,
1346
+ TOUCH = 2,
1347
+ STOP = 4,
1348
+};
1349
+
1350
+struct ceph_lease_walk_control {
1351
+ bool dir_lease;
1352
+ bool expire_dir_lease;
1353
+ unsigned long nr_to_scan;
1354
+ unsigned long dir_lease_ttl;
1355
+};
1356
+
1357
+static unsigned long
1358
+__dentry_leases_walk(struct ceph_mds_client *mdsc,
1359
+ struct ceph_lease_walk_control *lwc,
1360
+ int (*check)(struct dentry*, void*))
1361
+{
1362
+ struct ceph_dentry_info *di, *tmp;
1363
+ struct dentry *dentry, *last = NULL;
1364
+ struct list_head* list;
1365
+ LIST_HEAD(dispose);
1366
+ unsigned long freed = 0;
1367
+ int ret = 0;
1368
+
1369
+ list = lwc->dir_lease ? &mdsc->dentry_dir_leases : &mdsc->dentry_leases;
1370
+ spin_lock(&mdsc->dentry_list_lock);
1371
+ list_for_each_entry_safe(di, tmp, list, lease_list) {
1372
+ if (!lwc->nr_to_scan)
1373
+ break;
1374
+ --lwc->nr_to_scan;
1375
+
1376
+ dentry = di->dentry;
1377
+ if (last == dentry)
1378
+ break;
1379
+
1380
+ if (!spin_trylock(&dentry->d_lock))
1381
+ continue;
1382
+
1383
+ if (__lockref_is_dead(&dentry->d_lockref)) {
1384
+ list_del_init(&di->lease_list);
1385
+ goto next;
1386
+ }
1387
+
1388
+ ret = check(dentry, lwc);
1389
+ if (ret & TOUCH) {
1390
+ /* move it into tail of dir lease list */
1391
+ __dentry_dir_lease_touch(mdsc, di);
1392
+ if (!last)
1393
+ last = dentry;
1394
+ }
1395
+ if (ret & DELETE) {
1396
+ /* stale lease */
1397
+ di->flags &= ~CEPH_DENTRY_REFERENCED;
1398
+ if (dentry->d_lockref.count > 0) {
1399
+ /* update_dentry_lease() will re-add
1400
+ * it to lease list, or
1401
+ * ceph_d_delete() will return 1 when
1402
+ * last reference is dropped */
1403
+ list_del_init(&di->lease_list);
1404
+ } else {
1405
+ di->flags |= CEPH_DENTRY_SHRINK_LIST;
1406
+ list_move_tail(&di->lease_list, &dispose);
1407
+ dget_dlock(dentry);
1408
+ }
1409
+ }
1410
+next:
1411
+ spin_unlock(&dentry->d_lock);
1412
+ if (ret & STOP)
1413
+ break;
1414
+ }
1415
+ spin_unlock(&mdsc->dentry_list_lock);
1416
+
1417
+ while (!list_empty(&dispose)) {
1418
+ di = list_first_entry(&dispose, struct ceph_dentry_info,
1419
+ lease_list);
1420
+ dentry = di->dentry;
1421
+ spin_lock(&dentry->d_lock);
1422
+
1423
+ list_del_init(&di->lease_list);
1424
+ di->flags &= ~CEPH_DENTRY_SHRINK_LIST;
1425
+ if (di->flags & CEPH_DENTRY_REFERENCED) {
1426
+ spin_lock(&mdsc->dentry_list_lock);
1427
+ if (di->flags & CEPH_DENTRY_LEASE_LIST) {
1428
+ list_add_tail(&di->lease_list,
1429
+ &mdsc->dentry_leases);
1430
+ } else {
1431
+ __dentry_dir_lease_touch(mdsc, di);
1432
+ }
1433
+ spin_unlock(&mdsc->dentry_list_lock);
1434
+ } else {
1435
+ freed++;
1436
+ }
1437
+
1438
+ spin_unlock(&dentry->d_lock);
1439
+ /* ceph_d_delete() does the trick */
1440
+ dput(dentry);
1441
+ }
1442
+ return freed;
1443
+}
1444
+
1445
+static int __dentry_lease_check(struct dentry *dentry, void *arg)
1446
+{
1447
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
1448
+ int ret;
1449
+
1450
+ if (__dentry_lease_is_valid(di))
1451
+ return STOP;
1452
+ ret = __dir_lease_try_check(dentry);
1453
+ if (ret == -EBUSY)
1454
+ return KEEP;
1455
+ if (ret > 0)
1456
+ return TOUCH;
1457
+ return DELETE;
1458
+}
1459
+
1460
+static int __dir_lease_check(struct dentry *dentry, void *arg)
1461
+{
1462
+ struct ceph_lease_walk_control *lwc = arg;
1463
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
1464
+
1465
+ int ret = __dir_lease_try_check(dentry);
1466
+ if (ret == -EBUSY)
1467
+ return KEEP;
1468
+ if (ret > 0) {
1469
+ if (time_before(jiffies, di->time + lwc->dir_lease_ttl))
1470
+ return STOP;
1471
+ /* Move dentry to tail of dir lease list if we don't want
1472
+ * to delete it. So dentries in the list are checked in a
1473
+ * round robin manner */
1474
+ if (!lwc->expire_dir_lease)
1475
+ return TOUCH;
1476
+ if (dentry->d_lockref.count > 0 ||
1477
+ (di->flags & CEPH_DENTRY_REFERENCED))
1478
+ return TOUCH;
1479
+ /* invalidate dir lease */
1480
+ di->lease_shared_gen = 0;
1481
+ }
1482
+ return DELETE;
1483
+}
1484
+
1485
+int ceph_trim_dentries(struct ceph_mds_client *mdsc)
1486
+{
1487
+ struct ceph_lease_walk_control lwc;
1488
+ unsigned long count;
1489
+ unsigned long freed;
1490
+
1491
+ spin_lock(&mdsc->caps_list_lock);
1492
+ if (mdsc->caps_use_max > 0 &&
1493
+ mdsc->caps_use_count > mdsc->caps_use_max)
1494
+ count = mdsc->caps_use_count - mdsc->caps_use_max;
1495
+ else
1496
+ count = 0;
1497
+ spin_unlock(&mdsc->caps_list_lock);
1498
+
1499
+ lwc.dir_lease = false;
1500
+ lwc.nr_to_scan = CEPH_CAPS_PER_RELEASE * 2;
1501
+ freed = __dentry_leases_walk(mdsc, &lwc, __dentry_lease_check);
1502
+ if (!lwc.nr_to_scan) /* more invalid leases */
1503
+ return -EAGAIN;
1504
+
1505
+ if (lwc.nr_to_scan < CEPH_CAPS_PER_RELEASE)
1506
+ lwc.nr_to_scan = CEPH_CAPS_PER_RELEASE;
1507
+
1508
+ lwc.dir_lease = true;
1509
+ lwc.expire_dir_lease = freed < count;
1510
+ lwc.dir_lease_ttl = mdsc->fsc->mount_options->caps_wanted_delay_max * HZ;
1511
+ freed +=__dentry_leases_walk(mdsc, &lwc, __dir_lease_check);
1512
+ if (!lwc.nr_to_scan) /* more to check */
1513
+ return -EAGAIN;
1514
+
1515
+ return freed > 0 ? 1 : 0;
1516
+}
1517
+
1518
+/*
11281519 * Ensure a dentry lease will no longer revalidate.
11291520 */
11301521 void ceph_invalidate_dentry_lease(struct dentry *dentry)
11311522 {
1523
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
11321524 spin_lock(&dentry->d_lock);
1133
- ceph_dentry(dentry)->time = jiffies;
1134
- ceph_dentry(dentry)->lease_shared_gen = 0;
1525
+ di->time = jiffies;
1526
+ di->lease_shared_gen = 0;
1527
+ di->flags &= ~CEPH_DENTRY_PRIMARY_LINK;
1528
+ __dentry_lease_unlist(di);
11351529 spin_unlock(&dentry->d_lock);
11361530 }
11371531
....@@ -1139,52 +1533,65 @@
11391533 * Check if dentry lease is valid. If not, delete the lease. Try to
11401534 * renew if the least is more than half up.
11411535 */
1142
-static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
1143
- struct inode *dir)
1536
+static bool __dentry_lease_is_valid(struct ceph_dentry_info *di)
1537
+{
1538
+ struct ceph_mds_session *session;
1539
+
1540
+ if (!di->lease_gen)
1541
+ return false;
1542
+
1543
+ session = di->lease_session;
1544
+ if (session) {
1545
+ u32 gen;
1546
+ unsigned long ttl;
1547
+
1548
+ spin_lock(&session->s_gen_ttl_lock);
1549
+ gen = session->s_cap_gen;
1550
+ ttl = session->s_cap_ttl;
1551
+ spin_unlock(&session->s_gen_ttl_lock);
1552
+
1553
+ if (di->lease_gen == gen &&
1554
+ time_before(jiffies, ttl) &&
1555
+ time_before(jiffies, di->time))
1556
+ return true;
1557
+ }
1558
+ di->lease_gen = 0;
1559
+ return false;
1560
+}
1561
+
1562
+static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags)
11441563 {
11451564 struct ceph_dentry_info *di;
1146
- struct ceph_mds_session *s;
1147
- int valid = 0;
1148
- u32 gen;
1149
- unsigned long ttl;
11501565 struct ceph_mds_session *session = NULL;
11511566 u32 seq = 0;
1567
+ int valid = 0;
11521568
11531569 spin_lock(&dentry->d_lock);
11541570 di = ceph_dentry(dentry);
1155
- if (di && di->lease_session) {
1156
- s = di->lease_session;
1157
- spin_lock(&s->s_gen_ttl_lock);
1158
- gen = s->s_cap_gen;
1159
- ttl = s->s_cap_ttl;
1160
- spin_unlock(&s->s_gen_ttl_lock);
1571
+ if (di && __dentry_lease_is_valid(di)) {
1572
+ valid = 1;
11611573
1162
- if (di->lease_gen == gen &&
1163
- time_before(jiffies, di->time) &&
1164
- time_before(jiffies, ttl)) {
1165
- valid = 1;
1166
- if (di->lease_renew_after &&
1167
- time_after(jiffies, di->lease_renew_after)) {
1168
- /*
1169
- * We should renew. If we're in RCU walk mode
1170
- * though, we can't do that so just return
1171
- * -ECHILD.
1172
- */
1173
- if (flags & LOOKUP_RCU) {
1174
- valid = -ECHILD;
1175
- } else {
1176
- session = ceph_get_mds_session(s);
1177
- seq = di->lease_seq;
1178
- di->lease_renew_after = 0;
1179
- di->lease_renew_from = jiffies;
1180
- }
1574
+ if (di->lease_renew_after &&
1575
+ time_after(jiffies, di->lease_renew_after)) {
1576
+ /*
1577
+ * We should renew. If we're in RCU walk mode
1578
+ * though, we can't do that so just return
1579
+ * -ECHILD.
1580
+ */
1581
+ if (flags & LOOKUP_RCU) {
1582
+ valid = -ECHILD;
1583
+ } else {
1584
+ session = ceph_get_mds_session(di->lease_session);
1585
+ seq = di->lease_seq;
1586
+ di->lease_renew_after = 0;
1587
+ di->lease_renew_from = jiffies;
11811588 }
11821589 }
11831590 }
11841591 spin_unlock(&dentry->d_lock);
11851592
11861593 if (session) {
1187
- ceph_mdsc_lease_send_msg(session, dir, dentry,
1594
+ ceph_mdsc_lease_send_msg(session, dentry,
11881595 CEPH_MDS_LEASE_RENEW, seq);
11891596 ceph_put_mds_session(session);
11901597 }
....@@ -1193,21 +1600,67 @@
11931600 }
11941601
11951602 /*
1196
- * Check if directory-wide content lease/cap is valid.
1603
+ * Called under dentry->d_lock.
11971604 */
1198
-static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
1605
+static int __dir_lease_try_check(const struct dentry *dentry)
11991606 {
1200
- struct ceph_inode_info *ci = ceph_inode(dir);
12011607 struct ceph_dentry_info *di = ceph_dentry(dentry);
1608
+ struct inode *dir;
1609
+ struct ceph_inode_info *ci;
12021610 int valid = 0;
12031611
1612
+ if (!di->lease_shared_gen)
1613
+ return 0;
1614
+ if (IS_ROOT(dentry))
1615
+ return 0;
1616
+
1617
+ dir = d_inode(dentry->d_parent);
1618
+ ci = ceph_inode(dir);
1619
+
1620
+ if (spin_trylock(&ci->i_ceph_lock)) {
1621
+ if (atomic_read(&ci->i_shared_gen) == di->lease_shared_gen &&
1622
+ __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 0))
1623
+ valid = 1;
1624
+ spin_unlock(&ci->i_ceph_lock);
1625
+ } else {
1626
+ valid = -EBUSY;
1627
+ }
1628
+
1629
+ if (!valid)
1630
+ di->lease_shared_gen = 0;
1631
+ return valid;
1632
+}
1633
+
1634
+/*
1635
+ * Check if directory-wide content lease/cap is valid.
1636
+ */
1637
+static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry,
1638
+ struct ceph_mds_client *mdsc)
1639
+{
1640
+ struct ceph_inode_info *ci = ceph_inode(dir);
1641
+ int valid;
1642
+ int shared_gen;
1643
+
12041644 spin_lock(&ci->i_ceph_lock);
1205
- if (atomic_read(&ci->i_shared_gen) == di->lease_shared_gen)
1206
- valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
1645
+ valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
1646
+ if (valid) {
1647
+ __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
1648
+ shared_gen = atomic_read(&ci->i_shared_gen);
1649
+ }
12071650 spin_unlock(&ci->i_ceph_lock);
1208
- dout("dir_lease_is_valid dir %p v%u dentry %p v%u = %d\n",
1209
- dir, (unsigned)atomic_read(&ci->i_shared_gen),
1210
- dentry, (unsigned)di->lease_shared_gen, valid);
1651
+ if (valid) {
1652
+ struct ceph_dentry_info *di;
1653
+ spin_lock(&dentry->d_lock);
1654
+ di = ceph_dentry(dentry);
1655
+ if (dir == d_inode(dentry->d_parent) &&
1656
+ di && di->lease_shared_gen == shared_gen)
1657
+ __ceph_dentry_dir_lease_touch(di);
1658
+ else
1659
+ valid = 0;
1660
+ spin_unlock(&dentry->d_lock);
1661
+ }
1662
+ dout("dir_lease_is_valid dir %p v%u dentry %p = %d\n",
1663
+ dir, (unsigned)atomic_read(&ci->i_shared_gen), dentry, valid);
12111664 return valid;
12121665 }
12131666
....@@ -1218,50 +1671,54 @@
12181671 {
12191672 int valid = 0;
12201673 struct dentry *parent;
1221
- struct inode *dir;
1674
+ struct inode *dir, *inode;
1675
+ struct ceph_mds_client *mdsc;
12221676
12231677 if (flags & LOOKUP_RCU) {
12241678 parent = READ_ONCE(dentry->d_parent);
12251679 dir = d_inode_rcu(parent);
12261680 if (!dir)
12271681 return -ECHILD;
1682
+ inode = d_inode_rcu(dentry);
12281683 } else {
12291684 parent = dget_parent(dentry);
12301685 dir = d_inode(parent);
1686
+ inode = d_inode(dentry);
12311687 }
12321688
1233
- dout("d_revalidate %p '%pd' inode %p offset %lld\n", dentry,
1234
- dentry, d_inode(dentry), ceph_dentry(dentry)->offset);
1689
+ dout("d_revalidate %p '%pd' inode %p offset 0x%llx\n", dentry,
1690
+ dentry, inode, ceph_dentry(dentry)->offset);
1691
+
1692
+ mdsc = ceph_sb_to_client(dir->i_sb)->mdsc;
12351693
12361694 /* always trust cached snapped dentries, snapdir dentry */
12371695 if (ceph_snap(dir) != CEPH_NOSNAP) {
12381696 dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
1239
- dentry, d_inode(dentry));
1697
+ dentry, inode);
12401698 valid = 1;
1241
- } else if (d_really_is_positive(dentry) &&
1242
- ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) {
1699
+ } else if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
12431700 valid = 1;
12441701 } else {
1245
- valid = dentry_lease_is_valid(dentry, flags, dir);
1702
+ valid = dentry_lease_is_valid(dentry, flags);
12461703 if (valid == -ECHILD)
12471704 return valid;
1248
- if (valid || dir_lease_is_valid(dir, dentry)) {
1249
- if (d_really_is_positive(dentry))
1250
- valid = ceph_is_any_caps(d_inode(dentry));
1705
+ if (valid || dir_lease_is_valid(dir, dentry, mdsc)) {
1706
+ if (inode)
1707
+ valid = ceph_is_any_caps(inode);
12511708 else
12521709 valid = 1;
12531710 }
12541711 }
12551712
12561713 if (!valid) {
1257
- struct ceph_mds_client *mdsc =
1258
- ceph_sb_to_client(dir->i_sb)->mdsc;
12591714 struct ceph_mds_request *req;
12601715 int op, err;
12611716 u32 mask;
12621717
12631718 if (flags & LOOKUP_RCU)
12641719 return -ECHILD;
1720
+
1721
+ percpu_counter_inc(&mdsc->metric.d_lease_mis);
12651722
12661723 op = ceph_snap(dir) == CEPH_SNAPDIR ?
12671724 CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP;
....@@ -1286,7 +1743,7 @@
12861743 case -ENOENT:
12871744 if (d_really_is_negative(dentry))
12881745 valid = 1;
1289
- /* Fallthrough */
1746
+ fallthrough;
12901747 default:
12911748 break;
12921749 }
....@@ -1294,18 +1751,42 @@
12941751 dout("d_revalidate %p lookup result=%d\n",
12951752 dentry, err);
12961753 }
1754
+ } else {
1755
+ percpu_counter_inc(&mdsc->metric.d_lease_hit);
12971756 }
12981757
12991758 dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid");
1300
- if (valid) {
1301
- ceph_dentry_lru_touch(dentry);
1302
- } else {
1759
+ if (!valid)
13031760 ceph_dir_clear_complete(dir);
1304
- }
13051761
13061762 if (!(flags & LOOKUP_RCU))
13071763 dput(parent);
13081764 return valid;
1765
+}
1766
+
1767
+/*
1768
+ * Delete unused dentry that doesn't have valid lease
1769
+ *
1770
+ * Called under dentry->d_lock.
1771
+ */
1772
+static int ceph_d_delete(const struct dentry *dentry)
1773
+{
1774
+ struct ceph_dentry_info *di;
1775
+
1776
+ /* won't release caps */
1777
+ if (d_really_is_negative(dentry))
1778
+ return 0;
1779
+ if (ceph_snap(d_inode(dentry)) != CEPH_NOSNAP)
1780
+ return 0;
1781
+ /* vaild lease? */
1782
+ di = ceph_dentry(dentry);
1783
+ if (di) {
1784
+ if (__dentry_lease_is_valid(di))
1785
+ return 0;
1786
+ if (__dir_lease_try_check(dentry))
1787
+ return 0;
1788
+ }
1789
+ return 1;
13091790 }
13101791
13111792 /*
....@@ -1314,16 +1795,18 @@
13141795 static void ceph_d_release(struct dentry *dentry)
13151796 {
13161797 struct ceph_dentry_info *di = ceph_dentry(dentry);
1798
+ struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
13171799
13181800 dout("d_release %p\n", dentry);
1319
- ceph_dentry_lru_del(dentry);
1801
+
1802
+ atomic64_dec(&fsc->mdsc->metric.total_dentries);
13201803
13211804 spin_lock(&dentry->d_lock);
1805
+ __dentry_lease_unlist(di);
13221806 dentry->d_fsdata = NULL;
13231807 spin_unlock(&dentry->d_lock);
13241808
1325
- if (di->lease_session)
1326
- ceph_put_mds_session(di->lease_session);
1809
+ ceph_put_mds_session(di->lease_session);
13271810 kmem_cache_free(ceph_dentry_cachep, di);
13281811 }
13291812
....@@ -1419,49 +1902,7 @@
14191902 return size - left;
14201903 }
14211904
1422
-/*
1423
- * We maintain a private dentry LRU.
1424
- *
1425
- * FIXME: this needs to be changed to a per-mds lru to be useful.
1426
- */
1427
-void ceph_dentry_lru_add(struct dentry *dn)
1428
-{
1429
- struct ceph_dentry_info *di = ceph_dentry(dn);
1430
- struct ceph_mds_client *mdsc;
14311905
1432
- dout("dentry_lru_add %p %p '%pd'\n", di, dn, dn);
1433
- mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
1434
- spin_lock(&mdsc->dentry_lru_lock);
1435
- list_add_tail(&di->lru, &mdsc->dentry_lru);
1436
- mdsc->num_dentry++;
1437
- spin_unlock(&mdsc->dentry_lru_lock);
1438
-}
1439
-
1440
-void ceph_dentry_lru_touch(struct dentry *dn)
1441
-{
1442
- struct ceph_dentry_info *di = ceph_dentry(dn);
1443
- struct ceph_mds_client *mdsc;
1444
-
1445
- dout("dentry_lru_touch %p %p '%pd' (offset %lld)\n", di, dn, dn,
1446
- di->offset);
1447
- mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
1448
- spin_lock(&mdsc->dentry_lru_lock);
1449
- list_move_tail(&di->lru, &mdsc->dentry_lru);
1450
- spin_unlock(&mdsc->dentry_lru_lock);
1451
-}
1452
-
1453
-void ceph_dentry_lru_del(struct dentry *dn)
1454
-{
1455
- struct ceph_dentry_info *di = ceph_dentry(dn);
1456
- struct ceph_mds_client *mdsc;
1457
-
1458
- dout("dentry_lru_del %p %p '%pd'\n", di, dn, dn);
1459
- mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
1460
- spin_lock(&mdsc->dentry_lru_lock);
1461
- list_del_init(&di->lru);
1462
- mdsc->num_dentry--;
1463
- spin_unlock(&mdsc->dentry_lru_lock);
1464
-}
14651906
14661907 /*
14671908 * Return name hash for a given dentry. This is dependent on
....@@ -1493,6 +1934,7 @@
14931934 .open = ceph_open,
14941935 .release = ceph_release,
14951936 .unlocked_ioctl = ceph_ioctl,
1937
+ .compat_ioctl = compat_ptr_ioctl,
14961938 .fsync = ceph_fsync,
14971939 .lock = ceph_lock,
14981940 .flock = ceph_flock,
....@@ -1535,6 +1977,7 @@
15351977
15361978 const struct dentry_operations ceph_dentry_ops = {
15371979 .d_revalidate = ceph_d_revalidate,
1980
+ .d_delete = ceph_d_delete,
15381981 .d_release = ceph_d_release,
15391982 .d_prune = ceph_d_prune,
15401983 .d_init = ceph_d_init,