aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph/dir.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-26 16:38:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-26 16:38:50 -0400
commitba5b56cb3e3d2cab73d4fee9a022bb69462a8cd9 (patch)
treeeda7ea059a41ae5d68e2ad5a36a87069187ef22a /fs/ceph/dir.c
parent243dd2809a5edd2e0e3e62781083aa44049af37d (diff)
parentd79698da32b317e96216236f265a9b72b78ae568 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client: (23 commits) ceph: document unlocked d_parent accesses ceph: explicitly reference rename old_dentry parent dir in request ceph: document locking for ceph_set_dentry_offset ceph: avoid d_parent in ceph_dentry_hash; fix ceph_encode_fh() hashing bug ceph: protect d_parent access in ceph_d_revalidate ceph: protect access to d_parent ceph: handle racing calls to ceph_init_dentry ceph: set dir complete frag after adding capability rbd: set blk_queue request sizes to object size ceph: set up readahead size when rsize is not passed rbd: cancel watch request when releasing the device ceph: ignore lease mask ceph: fix ceph_lookup_open intent usage ceph: only link open operations to directory unsafe list if O_CREAT|O_TRUNC ceph: fix bad parent_inode calc in ceph_lookup_open ceph: avoid carrying Fw cap during write into page cache libceph: don't time out osd requests that haven't been received ceph: report f_bfree based on kb_avail rather than diffing. ceph: only queue capsnap if caps are dirty ceph: fix snap writeback when racing with writes ...
Diffstat (limited to 'fs/ceph/dir.c')
-rw-r--r--fs/ceph/dir.c116
1 files changed, 73 insertions, 43 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 1065ac779840..382abc9a6a54 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -40,14 +40,6 @@ int ceph_init_dentry(struct dentry *dentry)
40 if (dentry->d_fsdata) 40 if (dentry->d_fsdata)
41 return 0; 41 return 0;
42 42
43 if (dentry->d_parent == NULL || /* nfs fh_to_dentry */
44 ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
45 d_set_d_op(dentry, &ceph_dentry_ops);
46 else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
47 d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
48 else
49 d_set_d_op(dentry, &ceph_snap_dentry_ops);
50
51 di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO); 43 di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO);
52 if (!di) 44 if (!di)
53 return -ENOMEM; /* oh well */ 45 return -ENOMEM; /* oh well */
@@ -58,16 +50,42 @@ int ceph_init_dentry(struct dentry *dentry)
58 kmem_cache_free(ceph_dentry_cachep, di); 50 kmem_cache_free(ceph_dentry_cachep, di);
59 goto out_unlock; 51 goto out_unlock;
60 } 52 }
53
54 if (dentry->d_parent == NULL || /* nfs fh_to_dentry */
55 ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
56 d_set_d_op(dentry, &ceph_dentry_ops);
57 else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
58 d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
59 else
60 d_set_d_op(dentry, &ceph_snap_dentry_ops);
61
61 di->dentry = dentry; 62 di->dentry = dentry;
62 di->lease_session = NULL; 63 di->lease_session = NULL;
63 dentry->d_fsdata = di;
64 dentry->d_time = jiffies; 64 dentry->d_time = jiffies;
65 /* avoid reordering d_fsdata setup so that the check above is safe */
66 smp_mb();
67 dentry->d_fsdata = di;
65 ceph_dentry_lru_add(dentry); 68 ceph_dentry_lru_add(dentry);
66out_unlock: 69out_unlock:
67 spin_unlock(&dentry->d_lock); 70 spin_unlock(&dentry->d_lock);
68 return 0; 71 return 0;
69} 72}
70 73
74struct inode *ceph_get_dentry_parent_inode(struct dentry *dentry)
75{
76 struct inode *inode = NULL;
77
78 if (!dentry)
79 return NULL;
80
81 spin_lock(&dentry->d_lock);
82 if (dentry->d_parent) {
83 inode = dentry->d_parent->d_inode;
84 ihold(inode);
85 }
86 spin_unlock(&dentry->d_lock);
87 return inode;
88}
71 89
72 90
73/* 91/*
@@ -133,7 +151,7 @@ more:
133 d_unhashed(dentry) ? "!hashed" : "hashed", 151 d_unhashed(dentry) ? "!hashed" : "hashed",
134 parent->d_subdirs.prev, parent->d_subdirs.next); 152 parent->d_subdirs.prev, parent->d_subdirs.next);
135 if (p == &parent->d_subdirs) { 153 if (p == &parent->d_subdirs) {
136 fi->at_end = 1; 154 fi->flags |= CEPH_F_ATEND;
137 goto out_unlock; 155 goto out_unlock;
138 } 156 }
139 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 157 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
@@ -234,7 +252,7 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
234 const int max_bytes = fsc->mount_options->max_readdir_bytes; 252 const int max_bytes = fsc->mount_options->max_readdir_bytes;
235 253
236 dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off); 254 dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off);
237 if (fi->at_end) 255 if (fi->flags & CEPH_F_ATEND)
238 return 0; 256 return 0;
239 257
240 /* always start with . and .. */ 258 /* always start with . and .. */
@@ -403,7 +421,7 @@ more:
403 dout("readdir next frag is %x\n", frag); 421 dout("readdir next frag is %x\n", frag);
404 goto more; 422 goto more;
405 } 423 }
406 fi->at_end = 1; 424 fi->flags |= CEPH_F_ATEND;
407 425
408 /* 426 /*
409 * if dir_release_count still matches the dir, no dentries 427 * if dir_release_count still matches the dir, no dentries
@@ -435,7 +453,7 @@ static void reset_readdir(struct ceph_file_info *fi)
435 dput(fi->dentry); 453 dput(fi->dentry);
436 fi->dentry = NULL; 454 fi->dentry = NULL;
437 } 455 }
438 fi->at_end = 0; 456 fi->flags &= ~CEPH_F_ATEND;
439} 457}
440 458
441static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin) 459static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
@@ -463,7 +481,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
463 if (offset != file->f_pos) { 481 if (offset != file->f_pos) {
464 file->f_pos = offset; 482 file->f_pos = offset;
465 file->f_version = 0; 483 file->f_version = 0;
466 fi->at_end = 0; 484 fi->flags &= ~CEPH_F_ATEND;
467 } 485 }
468 retval = offset; 486 retval = offset;
469 487
@@ -488,21 +506,13 @@ out:
488} 506}
489 507
490/* 508/*
491 * Process result of a lookup/open request. 509 * Handle lookups for the hidden .snap directory.
492 *
493 * Mainly, make sure we return the final req->r_dentry (if it already
494 * existed) in place of the original VFS-provided dentry when they
495 * differ.
496 *
497 * Gracefully handle the case where the MDS replies with -ENOENT and
498 * no trace (which it may do, at its discretion, e.g., if it doesn't
499 * care to issue a lease on the negative dentry).
500 */ 510 */
501struct dentry *ceph_finish_lookup(struct ceph_mds_request *req, 511int ceph_handle_snapdir(struct ceph_mds_request *req,
502 struct dentry *dentry, int err) 512 struct dentry *dentry, int err)
503{ 513{
504 struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); 514 struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
505 struct inode *parent = dentry->d_parent->d_inode; 515 struct inode *parent = dentry->d_parent->d_inode; /* we hold i_mutex */
506 516
507 /* .snap dir? */ 517 /* .snap dir? */
508 if (err == -ENOENT && 518 if (err == -ENOENT &&
@@ -516,7 +526,23 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
516 d_add(dentry, inode); 526 d_add(dentry, inode);
517 err = 0; 527 err = 0;
518 } 528 }
529 return err;
530}
519 531
532/*
533 * Figure out final result of a lookup/open request.
534 *
535 * Mainly, make sure we return the final req->r_dentry (if it already
536 * existed) in place of the original VFS-provided dentry when they
537 * differ.
538 *
539 * Gracefully handle the case where the MDS replies with -ENOENT and
540 * no trace (which it may do, at its discretion, e.g., if it doesn't
541 * care to issue a lease on the negative dentry).
542 */
543struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
544 struct dentry *dentry, int err)
545{
520 if (err == -ENOENT) { 546 if (err == -ENOENT) {
521 /* no trace? */ 547 /* no trace? */
522 err = 0; 548 err = 0;
@@ -610,6 +636,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
610 req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE); 636 req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
611 req->r_locked_dir = dir; 637 req->r_locked_dir = dir;
612 err = ceph_mdsc_do_request(mdsc, NULL, req); 638 err = ceph_mdsc_do_request(mdsc, NULL, req);
639 err = ceph_handle_snapdir(req, dentry, err);
613 dentry = ceph_finish_lookup(req, dentry, err); 640 dentry = ceph_finish_lookup(req, dentry, err);
614 ceph_mdsc_put_request(req); /* will dput(dentry) */ 641 ceph_mdsc_put_request(req); /* will dput(dentry) */
615 dout("lookup result=%p\n", dentry); 642 dout("lookup result=%p\n", dentry);
@@ -789,6 +816,7 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
789 req->r_dentry = dget(dentry); 816 req->r_dentry = dget(dentry);
790 req->r_num_caps = 2; 817 req->r_num_caps = 2;
791 req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */ 818 req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */
819 req->r_old_dentry_dir = ceph_get_dentry_parent_inode(old_dentry);
792 req->r_locked_dir = dir; 820 req->r_locked_dir = dir;
793 req->r_dentry_drop = CEPH_CAP_FILE_SHARED; 821 req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
794 req->r_dentry_unless = CEPH_CAP_FILE_EXCL; 822 req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
@@ -887,6 +915,7 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
887 req->r_dentry = dget(new_dentry); 915 req->r_dentry = dget(new_dentry);
888 req->r_num_caps = 2; 916 req->r_num_caps = 2;
889 req->r_old_dentry = dget(old_dentry); 917 req->r_old_dentry = dget(old_dentry);
918 req->r_old_dentry_dir = ceph_get_dentry_parent_inode(old_dentry);
890 req->r_locked_dir = new_dir; 919 req->r_locked_dir = new_dir;
891 req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED; 920 req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED;
892 req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL; 921 req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL;
@@ -1002,36 +1031,38 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
1002 */ 1031 */
1003static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) 1032static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
1004{ 1033{
1034 int valid = 0;
1005 struct inode *dir; 1035 struct inode *dir;
1006 1036
1007 if (nd && nd->flags & LOOKUP_RCU) 1037 if (nd && nd->flags & LOOKUP_RCU)
1008 return -ECHILD; 1038 return -ECHILD;
1009 1039
1010 dir = dentry->d_parent->d_inode;
1011
1012 dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, 1040 dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
1013 dentry->d_name.len, dentry->d_name.name, dentry->d_inode, 1041 dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
1014 ceph_dentry(dentry)->offset); 1042 ceph_dentry(dentry)->offset);
1015 1043
1044 dir = ceph_get_dentry_parent_inode(dentry);
1045
1016 /* always trust cached snapped dentries, snapdir dentry */ 1046 /* always trust cached snapped dentries, snapdir dentry */
1017 if (ceph_snap(dir) != CEPH_NOSNAP) { 1047 if (ceph_snap(dir) != CEPH_NOSNAP) {
1018 dout("d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry, 1048 dout("d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry,
1019 dentry->d_name.len, dentry->d_name.name, dentry->d_inode); 1049 dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
1020 goto out_touch; 1050 valid = 1;
1051 } else if (dentry->d_inode &&
1052 ceph_snap(dentry->d_inode) == CEPH_SNAPDIR) {
1053 valid = 1;
1054 } else if (dentry_lease_is_valid(dentry) ||
1055 dir_lease_is_valid(dir, dentry)) {
1056 valid = 1;
1021 } 1057 }
1022 if (dentry->d_inode && ceph_snap(dentry->d_inode) == CEPH_SNAPDIR)
1023 goto out_touch;
1024
1025 if (dentry_lease_is_valid(dentry) ||
1026 dir_lease_is_valid(dir, dentry))
1027 goto out_touch;
1028 1058
1029 dout("d_revalidate %p invalid\n", dentry); 1059 dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid");
1030 d_drop(dentry); 1060 if (valid)
1031 return 0; 1061 ceph_dentry_lru_touch(dentry);
1032out_touch: 1062 else
1033 ceph_dentry_lru_touch(dentry); 1063 d_drop(dentry);
1034 return 1; 1064 iput(dir);
1065 return valid;
1035} 1066}
1036 1067
1037/* 1068/*
@@ -1228,9 +1259,8 @@ void ceph_dentry_lru_del(struct dentry *dn)
1228 * Return name hash for a given dentry. This is dependent on 1259 * Return name hash for a given dentry. This is dependent on
1229 * the parent directory's hash function. 1260 * the parent directory's hash function.
1230 */ 1261 */
1231unsigned ceph_dentry_hash(struct dentry *dn) 1262unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn)
1232{ 1263{
1233 struct inode *dir = dn->d_parent->d_inode;
1234 struct ceph_inode_info *dci = ceph_inode(dir); 1264 struct ceph_inode_info *dci = ceph_inode(dir);
1235 1265
1236 switch (dci->i_dir_layout.dl_dir_hash) { 1266 switch (dci->i_dir_layout.dl_dir_hash) {