Merge branch 'parisc-4.6-4' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[deliverable/linux.git] / fs / ceph / xattr.c
index 819163d8313bb3748765b5c3313dfdfd32ac9472..9410abdef3cec5fdb0ca73a905c503c10bc994fb 100644 (file)
@@ -714,31 +714,62 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
        }
 }
 
+static inline int __get_request_mask(struct inode *in) {
+       struct ceph_mds_request *req = current->journal_info;
+       int mask = 0;
+       if (req && req->r_target_inode == in) {
+               if (req->r_op == CEPH_MDS_OP_LOOKUP ||
+                   req->r_op == CEPH_MDS_OP_LOOKUPINO ||
+                   req->r_op == CEPH_MDS_OP_LOOKUPPARENT ||
+                   req->r_op == CEPH_MDS_OP_GETATTR) {
+                       mask = le32_to_cpu(req->r_args.getattr.mask);
+               } else if (req->r_op == CEPH_MDS_OP_OPEN ||
+                          req->r_op == CEPH_MDS_OP_CREATE) {
+                       mask = le32_to_cpu(req->r_args.open.mask);
+               }
+       }
+       return mask;
+}
+
 ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
                      size_t size)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int err;
        struct ceph_inode_xattr *xattr;
        struct ceph_vxattr *vxattr = NULL;
+       int req_mask;
+       int err;
 
        if (!ceph_is_valid_xattr(name))
                return -ENODATA;
 
        /* let's see if a virtual xattr was requested */
        vxattr = ceph_match_vxattr(inode, name);
-       if (vxattr && !(vxattr->exists_cb && !vxattr->exists_cb(ci))) {
-               err = vxattr->getxattr_cb(ci, value, size);
+       if (vxattr) {
+               err = -ENODATA;
+               if (!(vxattr->exists_cb && !vxattr->exists_cb(ci)))
+                       err = vxattr->getxattr_cb(ci, value, size);
                return err;
        }
 
+       req_mask = __get_request_mask(inode);
+
        spin_lock(&ci->i_ceph_lock);
        dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
             ci->i_xattrs.version, ci->i_xattrs.index_version);
 
        if (ci->i_xattrs.version == 0 ||
-           !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) {
+           !((req_mask & CEPH_CAP_XATTR_SHARED) ||
+             __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1))) {
                spin_unlock(&ci->i_ceph_lock);
+
+               /* security module gets xattr while filling trace */
+               if (current->journal_info != NULL) {
+                       pr_warn_ratelimited("sync getxattr %p "
+                                           "during filling trace\n", inode);
+                       return -EBUSY;
+               }
+
                /* get xattrs from mds (if we don't already have them) */
                err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
                if (err)
@@ -765,6 +796,9 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
 
        memcpy(value, xattr->val, xattr->val_len);
 
+       if (current->journal_info != NULL &&
+           !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN))
+               ci->i_ceph_flags |= CEPH_I_SEC_INITED;
 out:
        spin_unlock(&ci->i_ceph_lock);
        return err;
@@ -999,7 +1033,7 @@ retry:
                dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
                                               &prealloc_cf);
                ci->i_xattrs.dirty = true;
-               inode->i_ctime = CURRENT_TIME;
+               inode->i_ctime = current_fs_time(inode->i_sb);
        }
 
        spin_unlock(&ci->i_ceph_lock);
@@ -1015,7 +1049,15 @@ do_sync:
 do_sync_unlocked:
        if (lock_snap_rwsem)
                up_read(&mdsc->snap_rwsem);
-       err = ceph_sync_setxattr(dentry, name, value, size, flags);
+
+       /* security module set xattr while filling trace */
+       if (current->journal_info != NULL) {
+               pr_warn_ratelimited("sync setxattr %p "
+                                   "during filling trace\n", inode);
+               err = -EBUSY;
+       } else {
+               err = ceph_sync_setxattr(dentry, name, value, size, flags);
+       }
 out:
        ceph_free_cap_flush(prealloc_cf);
        kfree(newname);
@@ -1136,7 +1178,7 @@ retry:
        dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
                                       &prealloc_cf);
        ci->i_xattrs.dirty = true;
-       inode->i_ctime = CURRENT_TIME;
+       inode->i_ctime = current_fs_time(inode->i_sb);
        spin_unlock(&ci->i_ceph_lock);
        if (lock_snap_rwsem)
                up_read(&mdsc->snap_rwsem);
@@ -1164,3 +1206,25 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
 
        return __ceph_removexattr(dentry, name);
 }
+
+#ifdef CONFIG_SECURITY
+bool ceph_security_xattr_wanted(struct inode *in)
+{
+       return in->i_security != NULL;
+}
+
+bool ceph_security_xattr_deadlock(struct inode *in)
+{
+       struct ceph_inode_info *ci;
+       bool ret;
+       if (in->i_security == NULL)
+               return false;
+       ci = ceph_inode(in);
+       spin_lock(&ci->i_ceph_lock);
+       ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) &&
+             !(ci->i_xattrs.version > 0 &&
+               __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0));
+       spin_unlock(&ci->i_ceph_lock);
+       return ret;
+}
+#endif
This page took 0.025721 seconds and 5 git commands to generate.