diff options
Diffstat (limited to 'fs/btrfs/xattr.c')
-rw-r--r-- | fs/btrfs/xattr.c | 73 |
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 | |||
127 | again: | ||
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); | ||
142 | out: | 162 | out: |
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 | */ | ||
147 | int __btrfs_setxattr(struct btrfs_trans_handle *trans, | 170 | int __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) |