ceph: properly handle XATTR_CREATE and XATTR_REPLACE
authorYan, Zheng <zheng.z.yan@intel.com>
Tue, 11 Feb 2014 05:01:19 +0000 (13:01 +0800)
committerSage Weil <sage@inktank.com>
Mon, 17 Feb 2014 20:37:05 +0000 (12:37 -0800)
return -EEXIST if XATTR_CREATE is set and xattr alread exists.
return -ENODATA if XATTR_REPLACE is set but xattr does not exist.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
fs/ceph/xattr.c

index 898b6565ad3e2c114baca0282fafea6a5643071a..28f9793b9167791735e780f81518d92a529b00f0 100644 (file)
@@ -319,8 +319,7 @@ static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode,
 static int __set_xattr(struct ceph_inode_info *ci,
                           const char *name, int name_len,
                           const char *val, int val_len,
-                          int dirty,
-                          int should_free_name, int should_free_val,
+                          int flags, int update_xattr,
                           struct ceph_inode_xattr **newxattr)
 {
        struct rb_node **p;
@@ -349,12 +348,25 @@ static int __set_xattr(struct ceph_inode_info *ci,
                xattr = NULL;
        }
 
+       if (update_xattr) {
+               int err = 0;
+               if (xattr && (flags & XATTR_CREATE))
+                       err = -EEXIST;
+               else if (!xattr && (flags & XATTR_REPLACE))
+                       err = -ENODATA;
+               if (err) {
+                       kfree(name);
+                       kfree(val);
+                       return err;
+               }
+       }
+
        if (!xattr) {
                new = 1;
                xattr = *newxattr;
                xattr->name = name;
                xattr->name_len = name_len;
-               xattr->should_free_name = should_free_name;
+               xattr->should_free_name = update_xattr;
 
                ci->i_xattrs.count++;
                dout("__set_xattr count=%d\n", ci->i_xattrs.count);
@@ -364,7 +376,7 @@ static int __set_xattr(struct ceph_inode_info *ci,
                if (xattr->should_free_val)
                        kfree((void *)xattr->val);
 
-               if (should_free_name) {
+               if (update_xattr) {
                        kfree((void *)name);
                        name = xattr->name;
                }
@@ -379,8 +391,8 @@ static int __set_xattr(struct ceph_inode_info *ci,
                xattr->val = "";
 
        xattr->val_len = val_len;
-       xattr->dirty = dirty;
-       xattr->should_free_val = (val && should_free_val);
+       xattr->dirty = update_xattr;
+       xattr->should_free_val = (val && update_xattr);
 
        if (new) {
                rb_link_node(&xattr->node, parent, p);
@@ -588,7 +600,7 @@ start:
                        p += len;
 
                        err = __set_xattr(ci, name, namelen, val, len,
-                                         0, 0, 0, &xattrs[numattr]);
+                                         0, 0, &xattrs[numattr]);
 
                        if (err < 0)
                                goto bad;
@@ -892,7 +904,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
        struct ceph_inode_info *ci = ceph_inode(inode);
        int issued;
        int err;
-       int dirty;
+       int dirty = 0;
        int name_len = strlen(name);
        int val_len = size;
        char *newname = NULL;
@@ -954,11 +966,13 @@ retry:
        }
 
        err = __set_xattr(ci, newname, name_len, newval,
-                         val_len, 1, 1, 1, &xattr);
+                         val_len, flags, 1, &xattr);
 
-       dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
-       ci->i_xattrs.dirty = true;
-       inode->i_ctime = CURRENT_TIME;
+       if (!err) {
+               dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+               ci->i_xattrs.dirty = true;
+               inode->i_ctime = CURRENT_TIME;
+       }
 
        spin_unlock(&ci->i_ceph_lock);
        if (dirty)