ceph: support getting ceph.dir.pin vxattr
[linux-2.6-microblaze.git] / fs / ceph / inode.c
index 79dd5e6..e6012de 100644 (file)
@@ -548,17 +548,22 @@ void ceph_destroy_inode(struct inode *inode)
         */
        if (ci->i_snap_realm) {
                struct ceph_mds_client *mdsc =
-                       ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
-               struct ceph_snap_realm *realm = ci->i_snap_realm;
-
-               dout(" dropping residual ref to snap realm %p\n", realm);
-               spin_lock(&realm->inodes_with_caps_lock);
-               list_del_init(&ci->i_snap_realm_item);
-               ci->i_snap_realm = NULL;
-               if (realm->ino == ci->i_vino.ino)
-                       realm->inode = NULL;
-               spin_unlock(&realm->inodes_with_caps_lock);
-               ceph_put_snap_realm(mdsc, realm);
+                                       ceph_inode_to_client(inode)->mdsc;
+               if (ceph_snap(inode) == CEPH_NOSNAP) {
+                       struct ceph_snap_realm *realm = ci->i_snap_realm;
+                       dout(" dropping residual ref to snap realm %p\n",
+                            realm);
+                       spin_lock(&realm->inodes_with_caps_lock);
+                       list_del_init(&ci->i_snap_realm_item);
+                       ci->i_snap_realm = NULL;
+                       if (realm->ino == ci->i_vino.ino)
+                               realm->inode = NULL;
+                       spin_unlock(&realm->inodes_with_caps_lock);
+                       ceph_put_snap_realm(mdsc, realm);
+               } else {
+                       ceph_put_snapid_map(mdsc, ci->i_snapid_map);
+                       ci->i_snap_realm = NULL;
+               }
        }
 
        kfree(ci->i_symlink);
@@ -776,6 +781,9 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                pool_ns = ceph_find_or_create_string(iinfo->pool_ns_data,
                                                     iinfo->pool_ns_len);
 
+       if (ceph_snap(inode) != CEPH_NOSNAP && !ci->i_snapid_map)
+               ci->i_snapid_map = ceph_get_snapid_map(mdsc, ceph_snap(inode));
+
        spin_lock(&ci->i_ceph_lock);
 
        /*
@@ -869,6 +877,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                        ci->i_rbytes = le64_to_cpu(info->rbytes);
                        ci->i_rfiles = le64_to_cpu(info->rfiles);
                        ci->i_rsubdirs = le64_to_cpu(info->rsubdirs);
+                       ci->i_dir_pin = iinfo->dir_pin;
                        ceph_decode_timespec64(&ci->i_rctime, &info->rctime);
                }
        }
@@ -899,6 +908,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        case S_IFBLK:
        case S_IFCHR:
        case S_IFSOCK:
+               inode->i_blkbits = PAGE_SHIFT;
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
                inode->i_op = &ceph_file_iops;
                break;
@@ -1098,8 +1108,9 @@ out_unlock:
  * splice a dentry to an inode.
  * caller must hold directory i_mutex for this to be safe.
  */
-static struct dentry *splice_dentry(struct dentry *dn, struct inode *in)
+static int splice_dentry(struct dentry **pdn, struct inode *in)
 {
+       struct dentry *dn = *pdn;
        struct dentry *realdn;
 
        BUG_ON(d_inode(dn));
@@ -1132,28 +1143,23 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in)
        if (IS_ERR(realdn)) {
                pr_err("splice_dentry error %ld %p inode %p ino %llx.%llx\n",
                       PTR_ERR(realdn), dn, in, ceph_vinop(in));
-               dn = realdn;
-               /*
-                * Caller should release 'dn' in the case of error.
-                * If 'req->r_dentry' is passed to this function,
-                * caller should leave 'req->r_dentry' untouched.
-                */
-               goto out;
-       } else if (realdn) {
+               return PTR_ERR(realdn);
+       }
+
+       if (realdn) {
                dout("dn %p (%d) spliced with %p (%d) "
                     "inode %p ino %llx.%llx\n",
                     dn, d_count(dn),
                     realdn, d_count(realdn),
                     d_inode(realdn), ceph_vinop(d_inode(realdn)));
                dput(dn);
-               dn = realdn;
+               *pdn = realdn;
        } else {
                BUG_ON(!ceph_dentry(dn));
                dout("dn %p attached to %p ino %llx.%llx\n",
                     dn, d_inode(dn), ceph_vinop(d_inode(dn)));
        }
-out:
-       return dn;
+       return 0;
 }
 
 /*
@@ -1340,7 +1346,12 @@ retry_lookup:
                        dout("dn %p gets new offset %lld\n", req->r_old_dentry,
                             ceph_dentry(req->r_old_dentry)->offset);
 
-                       dn = req->r_old_dentry;  /* use old_dentry */
+                       /* swap r_dentry and r_old_dentry in case that
+                        * splice_dentry() gets called later. This is safe
+                        * because no other place will use them */
+                       req->r_dentry = req->r_old_dentry;
+                       req->r_old_dentry = dn;
+                       dn = req->r_dentry;
                }
 
                /* null dentry? */
@@ -1365,12 +1376,10 @@ retry_lookup:
                if (d_really_is_negative(dn)) {
                        ceph_dir_clear_ordered(dir);
                        ihold(in);
-                       dn = splice_dentry(dn, in);
-                       if (IS_ERR(dn)) {
-                               err = PTR_ERR(dn);
+                       err = splice_dentry(&req->r_dentry, in);
+                       if (err < 0)
                                goto done;
-                       }
-                       req->r_dentry = dn;  /* may have spliced */
+                       dn = req->r_dentry;  /* may have spliced */
                } else if (d_really_is_positive(dn) && d_inode(dn) != in) {
                        dout(" %p links to %p %llx.%llx, not %llx.%llx\n",
                             dn, d_inode(dn), ceph_vinop(d_inode(dn)),
@@ -1390,22 +1399,18 @@ retry_lookup:
        } else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
                    req->r_op == CEPH_MDS_OP_MKSNAP) &&
                   !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) {
-               struct dentry *dn = req->r_dentry;
                struct inode *dir = req->r_parent;
 
                /* fill out a snapdir LOOKUPSNAP dentry */
-               BUG_ON(!dn);
                BUG_ON(!dir);
                BUG_ON(ceph_snap(dir) != CEPH_SNAPDIR);
-               dout(" linking snapped dir %p to dn %p\n", in, dn);
+               BUG_ON(!req->r_dentry);
+               dout(" linking snapped dir %p to dn %p\n", in, req->r_dentry);
                ceph_dir_clear_ordered(dir);
                ihold(in);
-               dn = splice_dentry(dn, in);
-               if (IS_ERR(dn)) {
-                       err = PTR_ERR(dn);
+               err = splice_dentry(&req->r_dentry, in);
+               if (err < 0)
                        goto done;
-               }
-               req->r_dentry = dn;  /* may have spliced */
        } else if (rinfo->head->is_dentry) {
                struct ceph_vino *ptvino = NULL;
 
@@ -1669,8 +1674,6 @@ retry_lookup:
                }
 
                if (d_really_is_negative(dn)) {
-                       struct dentry *realdn;
-
                        if (ceph_security_xattr_deadlock(in)) {
                                dout(" skip splicing dn %p to inode %p"
                                     " (security xattr deadlock)\n", dn, in);
@@ -1679,13 +1682,9 @@ retry_lookup:
                                goto next_item;
                        }
 
-                       realdn = splice_dentry(dn, in);
-                       if (IS_ERR(realdn)) {
-                               err = PTR_ERR(realdn);
-                               d_drop(dn);
+                       err = splice_dentry(&dn, in);
+                       if (err < 0)
                                goto next_item;
-                       }
-                       dn = realdn;
                }
 
                ceph_dentry(dn)->offset = rde->offset;
@@ -1701,8 +1700,7 @@ retry_lookup:
                                err = ret;
                }
 next_item:
-               if (dn)
-                       dput(dn);
+               dput(dn);
        }
 out:
        if (err == 0 && skipped == 0) {
@@ -2271,10 +2269,11 @@ int ceph_getattr(const struct path *path, struct kstat *stat,
        if (!err) {
                generic_fillattr(inode, stat);
                stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
-               if (ceph_snap(inode) != CEPH_NOSNAP)
-                       stat->dev = ceph_snap(inode);
+               if (ceph_snap(inode) == CEPH_NOSNAP)
+                       stat->dev = inode->i_sb->s_dev;
                else
-                       stat->dev = 0;
+                       stat->dev = ci->i_snapid_map ? ci->i_snapid_map->dev : 0;
+
                if (S_ISDIR(inode->i_mode)) {
                        if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb),
                                                RBYTES))