aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/xattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/xattr.c')
-rw-r--r--fs/btrfs/xattr.c73
1 files changed, 48 insertions, 25 deletions
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index 5366fe452ab0..69565e5fc6a0 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -102,48 +102,71 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
102 if (!path) 102 if (!path)
103 return -ENOMEM; 103 return -ENOMEM;
104 104
105 /* first lets see if we already have this xattr */ 105 if (flags & XATTR_REPLACE) {
106 di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name, 106 di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name,
107 strlen(name), -1); 107 name_len, -1);
108 if (IS_ERR(di)) { 108 if (IS_ERR(di)) {
109 ret = PTR_ERR(di); 109 ret = PTR_ERR(di);
110 goto out; 110 goto out;
111 } 111 } else if (!di) {
112 112 ret = -ENODATA;
113 /* ok we already have this xattr, lets remove it */
114 if (di) {
115 /* if we want create only exit */
116 if (flags & XATTR_CREATE) {
117 ret = -EEXIST;
118 goto out; 113 goto out;
119 } 114 }
120
121 ret = btrfs_delete_one_dir_name(trans, root, path, di); 115 ret = btrfs_delete_one_dir_name(trans, root, path, di);
122 BUG_ON(ret); 116 if (ret)
117 goto out;
123 btrfs_release_path(path); 118 btrfs_release_path(path);
124 119
125 /* if we don't have a value then we are removing the xattr */ 120 /*
121 * remove the attribute
122 */
126 if (!value) 123 if (!value)
127 goto out; 124 goto out;
128 } else { 125 }
126
127again:
128 ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode),
129 name, name_len, value, size);
130 if (ret == -EEXIST) {
131 if (flags & XATTR_CREATE)
132 goto out;
133 /*
134 * We can't use the path we already have since we won't have the
135 * proper locking for a delete, so release the path and
136 * re-lookup to delete the thing.
137 */
129 btrfs_release_path(path); 138 btrfs_release_path(path);
139 di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode),
140 name, name_len, -1);
141 if (IS_ERR(di)) {
142 ret = PTR_ERR(di);
143 goto out;
144 } else if (!di) {
145 /* Shouldn't happen but just in case... */
146 btrfs_release_path(path);
147 goto again;
148 }
130 149
131 if (flags & XATTR_REPLACE) { 150 ret = btrfs_delete_one_dir_name(trans, root, path, di);
132 /* we couldn't find the attr to replace */ 151 if (ret)
133 ret = -ENODATA;
134 goto out; 152 goto out;
153
154 /*
155 * We have a value to set, so go back and try to insert it now.
156 */
157 if (value) {
158 btrfs_release_path(path);
159 goto again;
135 } 160 }
136 } 161 }
137
138 /* ok we have to create a completely new xattr */
139 ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode),
140 name, name_len, value, size);
141 BUG_ON(ret);
142out: 162out:
143 btrfs_free_path(path); 163 btrfs_free_path(path);
144 return ret; 164 return ret;
145} 165}
146 166
167/*
168 * @value: "" makes the attribute to empty, NULL removes it
169 */
147int __btrfs_setxattr(struct btrfs_trans_handle *trans, 170int __btrfs_setxattr(struct btrfs_trans_handle *trans,
148 struct inode *inode, const char *name, 171 struct inode *inode, const char *name,
149 const void *value, size_t size, int flags) 172 const void *value, size_t size, int flags)