diff options
Diffstat (limited to 'fs/ceph')
| -rw-r--r-- | fs/ceph/dir.c | 28 | ||||
| -rw-r--r-- | fs/ceph/inode.c | 38 | ||||
| -rw-r--r-- | fs/ceph/mds_client.c | 2 | ||||
| -rw-r--r-- | fs/ceph/super.h | 2 |
4 files changed, 46 insertions, 24 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index d902948a90d8..fa7ca04ee816 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
| @@ -42,11 +42,11 @@ int ceph_init_dentry(struct dentry *dentry) | |||
| 42 | 42 | ||
| 43 | if (dentry->d_parent == NULL || /* nfs fh_to_dentry */ | 43 | if (dentry->d_parent == NULL || /* nfs fh_to_dentry */ |
| 44 | ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) | 44 | ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) |
| 45 | dentry->d_op = &ceph_dentry_ops; | 45 | d_set_d_op(dentry, &ceph_dentry_ops); |
| 46 | else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR) | 46 | else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR) |
| 47 | dentry->d_op = &ceph_snapdir_dentry_ops; | 47 | d_set_d_op(dentry, &ceph_snapdir_dentry_ops); |
| 48 | else | 48 | else |
| 49 | dentry->d_op = &ceph_snap_dentry_ops; | 49 | d_set_d_op(dentry, &ceph_snap_dentry_ops); |
| 50 | 50 | ||
| 51 | di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO); | 51 | di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO); |
| 52 | if (!di) | 52 | if (!di) |
| @@ -112,7 +112,7 @@ static int __dcache_readdir(struct file *filp, | |||
| 112 | dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos, | 112 | dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos, |
| 113 | last); | 113 | last); |
| 114 | 114 | ||
| 115 | spin_lock(&dcache_lock); | 115 | spin_lock(&parent->d_lock); |
| 116 | 116 | ||
| 117 | /* start at beginning? */ | 117 | /* start at beginning? */ |
| 118 | if (filp->f_pos == 2 || last == NULL || | 118 | if (filp->f_pos == 2 || last == NULL || |
| @@ -136,6 +136,7 @@ more: | |||
| 136 | fi->at_end = 1; | 136 | fi->at_end = 1; |
| 137 | goto out_unlock; | 137 | goto out_unlock; |
| 138 | } | 138 | } |
| 139 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
| 139 | if (!d_unhashed(dentry) && dentry->d_inode && | 140 | if (!d_unhashed(dentry) && dentry->d_inode && |
| 140 | ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && | 141 | ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && |
| 141 | ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && | 142 | ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && |
| @@ -145,13 +146,15 @@ more: | |||
| 145 | dentry->d_name.len, dentry->d_name.name, di->offset, | 146 | dentry->d_name.len, dentry->d_name.name, di->offset, |
| 146 | filp->f_pos, d_unhashed(dentry) ? " unhashed" : "", | 147 | filp->f_pos, d_unhashed(dentry) ? " unhashed" : "", |
| 147 | !dentry->d_inode ? " null" : ""); | 148 | !dentry->d_inode ? " null" : ""); |
| 149 | spin_unlock(&dentry->d_lock); | ||
| 148 | p = p->prev; | 150 | p = p->prev; |
| 149 | dentry = list_entry(p, struct dentry, d_u.d_child); | 151 | dentry = list_entry(p, struct dentry, d_u.d_child); |
| 150 | di = ceph_dentry(dentry); | 152 | di = ceph_dentry(dentry); |
| 151 | } | 153 | } |
| 152 | 154 | ||
| 153 | atomic_inc(&dentry->d_count); | 155 | dget_dlock(dentry); |
| 154 | spin_unlock(&dcache_lock); | 156 | spin_unlock(&dentry->d_lock); |
| 157 | spin_unlock(&parent->d_lock); | ||
| 155 | 158 | ||
| 156 | dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, | 159 | dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, |
| 157 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); | 160 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); |
| @@ -177,19 +180,19 @@ more: | |||
| 177 | 180 | ||
| 178 | filp->f_pos++; | 181 | filp->f_pos++; |
| 179 | 182 | ||
| 180 | /* make sure a dentry wasn't dropped while we didn't have dcache_lock */ | 183 | /* make sure a dentry wasn't dropped while we didn't have parent lock */ |
| 181 | if (!ceph_i_test(dir, CEPH_I_COMPLETE)) { | 184 | if (!ceph_i_test(dir, CEPH_I_COMPLETE)) { |
| 182 | dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); | 185 | dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); |
| 183 | err = -EAGAIN; | 186 | err = -EAGAIN; |
| 184 | goto out; | 187 | goto out; |
| 185 | } | 188 | } |
| 186 | 189 | ||
| 187 | spin_lock(&dcache_lock); | 190 | spin_lock(&parent->d_lock); |
| 188 | p = p->prev; /* advance to next dentry */ | 191 | p = p->prev; /* advance to next dentry */ |
| 189 | goto more; | 192 | goto more; |
| 190 | 193 | ||
| 191 | out_unlock: | 194 | out_unlock: |
| 192 | spin_unlock(&dcache_lock); | 195 | spin_unlock(&parent->d_lock); |
| 193 | out: | 196 | out: |
| 194 | if (last) | 197 | if (last) |
| 195 | dput(last); | 198 | dput(last); |
| @@ -987,7 +990,12 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry) | |||
| 987 | */ | 990 | */ |
| 988 | static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) | 991 | static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) |
| 989 | { | 992 | { |
| 990 | struct inode *dir = dentry->d_parent->d_inode; | 993 | struct inode *dir; |
| 994 | |||
| 995 | if (nd->flags & LOOKUP_RCU) | ||
| 996 | return -ECHILD; | ||
| 997 | |||
| 998 | dir = dentry->d_parent->d_inode; | ||
| 991 | 999 | ||
| 992 | dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, | 1000 | dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, |
| 993 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode, | 1001 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode, |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index bf1286588f26..e61de4f7b99d 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
| @@ -368,6 +368,15 @@ struct inode *ceph_alloc_inode(struct super_block *sb) | |||
| 368 | return &ci->vfs_inode; | 368 | return &ci->vfs_inode; |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | static void ceph_i_callback(struct rcu_head *head) | ||
| 372 | { | ||
| 373 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
| 374 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
| 375 | |||
| 376 | INIT_LIST_HEAD(&inode->i_dentry); | ||
| 377 | kmem_cache_free(ceph_inode_cachep, ci); | ||
| 378 | } | ||
| 379 | |||
| 371 | void ceph_destroy_inode(struct inode *inode) | 380 | void ceph_destroy_inode(struct inode *inode) |
| 372 | { | 381 | { |
| 373 | struct ceph_inode_info *ci = ceph_inode(inode); | 382 | struct ceph_inode_info *ci = ceph_inode(inode); |
| @@ -407,7 +416,7 @@ void ceph_destroy_inode(struct inode *inode) | |||
| 407 | if (ci->i_xattrs.prealloc_blob) | 416 | if (ci->i_xattrs.prealloc_blob) |
| 408 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); | 417 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); |
| 409 | 418 | ||
| 410 | kmem_cache_free(ceph_inode_cachep, ci); | 419 | call_rcu(&inode->i_rcu, ceph_i_callback); |
| 411 | } | 420 | } |
| 412 | 421 | ||
| 413 | 422 | ||
| @@ -841,13 +850,13 @@ static void ceph_set_dentry_offset(struct dentry *dn) | |||
| 841 | di->offset = ceph_inode(inode)->i_max_offset++; | 850 | di->offset = ceph_inode(inode)->i_max_offset++; |
| 842 | spin_unlock(&inode->i_lock); | 851 | spin_unlock(&inode->i_lock); |
| 843 | 852 | ||
| 844 | spin_lock(&dcache_lock); | 853 | spin_lock(&dir->d_lock); |
| 845 | spin_lock(&dn->d_lock); | 854 | spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); |
| 846 | list_move(&dn->d_u.d_child, &dir->d_subdirs); | 855 | list_move(&dn->d_u.d_child, &dir->d_subdirs); |
| 847 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, | 856 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, |
| 848 | dn->d_u.d_child.prev, dn->d_u.d_child.next); | 857 | dn->d_u.d_child.prev, dn->d_u.d_child.next); |
| 849 | spin_unlock(&dn->d_lock); | 858 | spin_unlock(&dn->d_lock); |
| 850 | spin_unlock(&dcache_lock); | 859 | spin_unlock(&dir->d_lock); |
| 851 | } | 860 | } |
| 852 | 861 | ||
| 853 | /* | 862 | /* |
| @@ -879,8 +888,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, | |||
| 879 | } else if (realdn) { | 888 | } else if (realdn) { |
| 880 | dout("dn %p (%d) spliced with %p (%d) " | 889 | dout("dn %p (%d) spliced with %p (%d) " |
| 881 | "inode %p ino %llx.%llx\n", | 890 | "inode %p ino %llx.%llx\n", |
| 882 | dn, atomic_read(&dn->d_count), | 891 | dn, dn->d_count, |
| 883 | realdn, atomic_read(&realdn->d_count), | 892 | realdn, realdn->d_count, |
| 884 | realdn->d_inode, ceph_vinop(realdn->d_inode)); | 893 | realdn->d_inode, ceph_vinop(realdn->d_inode)); |
| 885 | dput(dn); | 894 | dput(dn); |
| 886 | dn = realdn; | 895 | dn = realdn; |
| @@ -1231,11 +1240,11 @@ retry_lookup: | |||
| 1231 | goto retry_lookup; | 1240 | goto retry_lookup; |
| 1232 | } else { | 1241 | } else { |
| 1233 | /* reorder parent's d_subdirs */ | 1242 | /* reorder parent's d_subdirs */ |
| 1234 | spin_lock(&dcache_lock); | 1243 | spin_lock(&parent->d_lock); |
| 1235 | spin_lock(&dn->d_lock); | 1244 | spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); |
| 1236 | list_move(&dn->d_u.d_child, &parent->d_subdirs); | 1245 | list_move(&dn->d_u.d_child, &parent->d_subdirs); |
| 1237 | spin_unlock(&dn->d_lock); | 1246 | spin_unlock(&dn->d_lock); |
| 1238 | spin_unlock(&dcache_lock); | 1247 | spin_unlock(&parent->d_lock); |
| 1239 | } | 1248 | } |
| 1240 | 1249 | ||
| 1241 | di = dn->d_fsdata; | 1250 | di = dn->d_fsdata; |
| @@ -1772,12 +1781,17 @@ int ceph_do_getattr(struct inode *inode, int mask) | |||
| 1772 | * Check inode permissions. We verify we have a valid value for | 1781 | * Check inode permissions. We verify we have a valid value for |
| 1773 | * the AUTH cap, then call the generic handler. | 1782 | * the AUTH cap, then call the generic handler. |
| 1774 | */ | 1783 | */ |
| 1775 | int ceph_permission(struct inode *inode, int mask) | 1784 | int ceph_permission(struct inode *inode, int mask, unsigned int flags) |
| 1776 | { | 1785 | { |
| 1777 | int err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED); | 1786 | int err; |
| 1787 | |||
| 1788 | if (flags & IPERM_FLAG_RCU) | ||
| 1789 | return -ECHILD; | ||
| 1790 | |||
| 1791 | err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED); | ||
| 1778 | 1792 | ||
| 1779 | if (!err) | 1793 | if (!err) |
| 1780 | err = generic_permission(inode, mask, NULL); | 1794 | err = generic_permission(inode, mask, flags, NULL); |
| 1781 | return err; | 1795 | return err; |
| 1782 | } | 1796 | } |
| 1783 | 1797 | ||
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 38800eaa81d0..a50fca1e03be 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
| @@ -1486,7 +1486,7 @@ retry: | |||
| 1486 | *base = ceph_ino(temp->d_inode); | 1486 | *base = ceph_ino(temp->d_inode); |
| 1487 | *plen = len; | 1487 | *plen = len; |
| 1488 | dout("build_path on %p %d built %llx '%.*s'\n", | 1488 | dout("build_path on %p %d built %llx '%.*s'\n", |
| 1489 | dentry, atomic_read(&dentry->d_count), *base, len, path); | 1489 | dentry, dentry->d_count, *base, len, path); |
| 1490 | return path; | 1490 | return path; |
| 1491 | } | 1491 | } |
| 1492 | 1492 | ||
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 7f01728a4657..4553d8829edb 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
| @@ -665,7 +665,7 @@ extern void ceph_queue_invalidate(struct inode *inode); | |||
| 665 | extern void ceph_queue_writeback(struct inode *inode); | 665 | extern void ceph_queue_writeback(struct inode *inode); |
| 666 | 666 | ||
| 667 | extern int ceph_do_getattr(struct inode *inode, int mask); | 667 | extern int ceph_do_getattr(struct inode *inode, int mask); |
| 668 | extern int ceph_permission(struct inode *inode, int mask); | 668 | extern int ceph_permission(struct inode *inode, int mask, unsigned int flags); |
| 669 | extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); | 669 | extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); |
| 670 | extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, | 670 | extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, |
| 671 | struct kstat *stat); | 671 | struct kstat *stat); |
