|
@@ -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)
|