]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/btrfs/xattr.c
btrfs: optmize listxattr
[net-next-2.6.git] / fs / btrfs / xattr.c
CommitLineData
5103e947
JB
1/*
2 * Copyright (C) 2007 Red Hat. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
17 */
18
19#include <linux/init.h>
20#include <linux/fs.h>
21#include <linux/slab.h>
22#include <linux/rwsem.h>
23#include <linux/xattr.h>
24#include "ctree.h"
25#include "btrfs_inode.h"
26#include "transaction.h"
27#include "xattr.h"
28#include "disk-io.h"
33268eaf 29
5103e947
JB
30static struct xattr_handler *btrfs_xattr_handler_map[] = {
31 [BTRFS_XATTR_INDEX_USER] = &btrfs_xattr_user_handler,
caaca38b 32#ifdef CONFIG_FS_POSIX_ACL
33268eaf
JB
33 [BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS] = &btrfs_xattr_acl_access_handler,
34 [BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &btrfs_xattr_acl_default_handler,
caaca38b 35#endif
5103e947
JB
36 [BTRFS_XATTR_INDEX_TRUSTED] = &btrfs_xattr_trusted_handler,
37 [BTRFS_XATTR_INDEX_SECURITY] = &btrfs_xattr_security_handler,
33268eaf 38 [BTRFS_XATTR_INDEX_SYSTEM] = &btrfs_xattr_system_handler,
5103e947 39};
33268eaf 40
5103e947
JB
41struct xattr_handler *btrfs_xattr_handlers[] = {
42 &btrfs_xattr_user_handler,
caaca38b 43#ifdef CONFIG_FS_POSIX_ACL
33268eaf
JB
44 &btrfs_xattr_acl_access_handler,
45 &btrfs_xattr_acl_default_handler,
caaca38b 46#endif
5103e947
JB
47 &btrfs_xattr_trusted_handler,
48 &btrfs_xattr_security_handler,
33268eaf 49 &btrfs_xattr_system_handler,
5103e947
JB
50 NULL,
51};
52
5103e947
JB
53/*
54 * @param name_index - the index for the xattr handler
55 * @return the xattr_handler if we found it, NULL otherwise
56 *
57 * use this if we know the type of the xattr already
58 */
59static struct xattr_handler *btrfs_xattr_handler(int name_index)
60{
61 struct xattr_handler *handler = NULL;
62
63 if (name_index >= 0 &&
64 name_index < ARRAY_SIZE(btrfs_xattr_handler_map))
65 handler = btrfs_xattr_handler_map[name_index];
66
67 return handler;
68}
69
70static inline char *get_name(const char *name, int name_index)
71{
72 char *ret = NULL;
73 struct xattr_handler *handler = btrfs_xattr_handler(name_index);
74 int prefix_len;
75
76 if (!handler)
77 return ret;
78
79 prefix_len = strlen(handler->prefix);
80
81 ret = kmalloc(strlen(name) + prefix_len + 1, GFP_KERNEL);
82 if (!ret)
83 return ret;
84
85 memcpy(ret, handler->prefix, prefix_len);
86 memcpy(ret+prefix_len, name, strlen(name));
87 ret[prefix_len + strlen(name)] = '\0';
88
89 return ret;
90}
91
5103e947
JB
92ssize_t btrfs_xattr_get(struct inode *inode, int name_index,
93 const char *attr_name, void *buffer, size_t size)
94{
95 struct btrfs_dir_item *di;
96 struct btrfs_root *root = BTRFS_I(inode)->root;
97 struct btrfs_path *path;
98 struct extent_buffer *leaf;
99 struct xattr_handler *handler = btrfs_xattr_handler(name_index);
100 int ret = 0;
101 unsigned long data_ptr;
102 char *name;
103
104 if (!handler)
105 return -EOPNOTSUPP;
5103e947
JB
106 name = get_name(attr_name, name_index);
107 if (!name)
108 return -ENOMEM;
109
110 path = btrfs_alloc_path();
111 if (!path) {
112 kfree(name);
113 return -ENOMEM;
114 }
115
5103e947
JB
116 /* lookup the xattr by name */
117 di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name,
118 strlen(name), 0);
119 if (!di || IS_ERR(di)) {
120 ret = -ENODATA;
121 goto out;
122 }
123
124 leaf = path->nodes[0];
125 /* if size is 0, that means we want the size of the attr */
126 if (!size) {
127 ret = btrfs_dir_data_len(leaf, di);
128 goto out;
129 }
130
131 /* now get the data out of our dir_item */
132 if (btrfs_dir_data_len(leaf, di) > size) {
133 ret = -ERANGE;
134 goto out;
135 }
136 data_ptr = (unsigned long)((char *)(di + 1) +
137 btrfs_dir_name_len(leaf, di));
138 read_extent_buffer(leaf, buffer, data_ptr,
3acd7ee8 139 btrfs_dir_data_len(leaf, di));
5103e947
JB
140 ret = btrfs_dir_data_len(leaf, di);
141
142out:
5103e947
JB
143 kfree(name);
144 btrfs_free_path(path);
145 return ret;
146}
147
148int btrfs_xattr_set(struct inode *inode, int name_index,
149 const char *attr_name, const void *value, size_t size,
150 int flags)
151{
152 struct btrfs_dir_item *di;
153 struct btrfs_root *root = BTRFS_I(inode)->root;
154 struct btrfs_trans_handle *trans;
155 struct btrfs_path *path;
156 struct xattr_handler *handler = btrfs_xattr_handler(name_index);
157 char *name;
158 int ret = 0, mod = 0;
5103e947
JB
159 if (!handler)
160 return -EOPNOTSUPP;
5103e947
JB
161 name = get_name(attr_name, name_index);
162 if (!name)
163 return -ENOMEM;
164
165 path = btrfs_alloc_path();
166 if (!path) {
167 kfree(name);
168 return -ENOMEM;
169 }
170
5103e947
JB
171 trans = btrfs_start_transaction(root, 1);
172 btrfs_set_trans_block_group(trans, inode);
173
174 /* first lets see if we already have this xattr */
175 di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
176 strlen(name), -1);
177 if (IS_ERR(di)) {
178 ret = PTR_ERR(di);
179 goto out;
180 }
181
182 /* ok we already have this xattr, lets remove it */
183 if (di) {
184 /* if we want create only exit */
185 if (flags & XATTR_CREATE) {
186 ret = -EEXIST;
187 goto out;
188 }
189
190 ret = btrfs_delete_one_dir_name(trans, root, path, di);
191 if (ret)
192 goto out;
193 btrfs_release_path(root, path);
194
195 /* if we don't have a value then we are removing the xattr */
196 if (!value) {
197 mod = 1;
198 goto out;
199 }
33268eaf
JB
200 } else {
201 btrfs_release_path(root, path);
202
203 if (flags & XATTR_REPLACE) {
204 /* we couldn't find the attr to replace */
205 ret = -ENODATA;
206 goto out;
207 }
5103e947
JB
208 }
209
210 /* ok we have to create a completely new xattr */
211 ret = btrfs_insert_xattr_item(trans, root, name, strlen(name),
212 value, size, inode->i_ino);
213 if (ret)
214 goto out;
215 mod = 1;
216
217out:
218 if (mod) {
219 inode->i_ctime = CURRENT_TIME;
220 ret = btrfs_update_inode(trans, root, inode);
221 }
222
223 btrfs_end_transaction(trans, root);
5103e947
JB
224 kfree(name);
225 btrfs_free_path(path);
226
227 return ret;
228}
229
230ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
231{
232 struct btrfs_key key, found_key;
233 struct inode *inode = dentry->d_inode;
234 struct btrfs_root *root = BTRFS_I(inode)->root;
235 struct btrfs_path *path;
236 struct btrfs_item *item;
237 struct extent_buffer *leaf;
238 struct btrfs_dir_item *di;
5103e947 239 int ret = 0, slot, advance;
eaa47d86 240 size_t total_size = 0, size_left = size;
5103e947 241 unsigned long name_ptr;
eaa47d86 242 size_t name_len;
5103e947
JB
243 u32 nritems;
244
245 /*
246 * ok we want all objects associated with this id.
247 * NOTE: we set key.offset = 0; because we want to start with the
248 * first xattr that we find and walk forward
249 */
250 key.objectid = inode->i_ino;
251 btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
252 key.offset = 0;
253
254 path = btrfs_alloc_path();
5103e947
JB
255 if (!path)
256 return -ENOMEM;
1caf9342 257 path->reada = 2;
5103e947 258
5103e947
JB
259 /* search for our xattrs */
260 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
261 if (ret < 0)
262 goto err;
263 ret = 0;
264 advance = 0;
265 while (1) {
266 leaf = path->nodes[0];
267 nritems = btrfs_header_nritems(leaf);
268 slot = path->slots[0];
269
270 /* this is where we start walking through the path */
271 if (advance || slot >= nritems) {
272 /*
273 * if we've reached the last slot in this leaf we need
274 * to go to the next leaf and reset everything
275 */
276 if (slot >= nritems-1) {
277 ret = btrfs_next_leaf(root, path);
278 if (ret)
279 break;
280 leaf = path->nodes[0];
281 nritems = btrfs_header_nritems(leaf);
282 slot = path->slots[0];
283 } else {
284 /*
285 * just walking through the slots on this leaf
286 */
287 slot++;
288 path->slots[0]++;
289 }
290 }
291 advance = 1;
292
293 item = btrfs_item_nr(leaf, slot);
294 btrfs_item_key_to_cpu(leaf, &found_key, slot);
295
296 /* check to make sure this item is what we want */
297 if (found_key.objectid != key.objectid)
298 break;
299 if (btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY)
300 break;
301
302 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
303
eaa47d86
CH
304 name_len = btrfs_dir_name_len(leaf, di);
305 total_size += name_len + 1;
5103e947
JB
306
307 /* we are just looking for how big our buffer needs to be */
308 if (!size)
309 continue;
310
eaa47d86 311 if (!buffer || (name_len + 1) > size_left) {
5103e947
JB
312 ret = -ERANGE;
313 break;
314 }
315
eaa47d86
CH
316 name_ptr = (unsigned long)(di + 1);
317 read_extent_buffer(leaf, buffer, name_ptr, name_len);
318 buffer[name_len] = '\0';
319
320 size_left -= name_len + 1;
321 buffer += name_len + 1;
5103e947
JB
322 }
323 ret = total_size;
324
325err:
5103e947
JB
326 btrfs_free_path(path);
327
328 return ret;
329}
330
5103e947
JB
331/*
332 * Handler functions
333 */
334#define BTRFS_XATTR_SETGET_FUNCS(name, index) \
335static int btrfs_xattr_##name##_get(struct inode *inode, \
336 const char *name, void *value, \
337 size_t size) \
338{ \
744f52f9
Y
339 if (*name == '\0') \
340 return -EINVAL; \
5103e947
JB
341 return btrfs_xattr_get(inode, index, name, value, size); \
342} \
343static int btrfs_xattr_##name##_set(struct inode *inode, \
344 const char *name, const void *value,\
345 size_t size, int flags) \
346{ \
744f52f9
Y
347 if (*name == '\0') \
348 return -EINVAL; \
5103e947 349 return btrfs_xattr_set(inode, index, name, value, size, flags); \
69a32ac5
CM
350}
351
5103e947
JB
352BTRFS_XATTR_SETGET_FUNCS(security, BTRFS_XATTR_INDEX_SECURITY);
353BTRFS_XATTR_SETGET_FUNCS(system, BTRFS_XATTR_INDEX_SYSTEM);
354BTRFS_XATTR_SETGET_FUNCS(user, BTRFS_XATTR_INDEX_USER);
355BTRFS_XATTR_SETGET_FUNCS(trusted, BTRFS_XATTR_INDEX_TRUSTED);
356
357struct xattr_handler btrfs_xattr_security_handler = {
358 .prefix = XATTR_SECURITY_PREFIX,
5103e947
JB
359 .get = btrfs_xattr_security_get,
360 .set = btrfs_xattr_security_set,
361};
362
363struct xattr_handler btrfs_xattr_system_handler = {
364 .prefix = XATTR_SYSTEM_PREFIX,
5103e947
JB
365 .get = btrfs_xattr_system_get,
366 .set = btrfs_xattr_system_set,
367};
368
369struct xattr_handler btrfs_xattr_user_handler = {
370 .prefix = XATTR_USER_PREFIX,
5103e947
JB
371 .get = btrfs_xattr_user_get,
372 .set = btrfs_xattr_user_set,
373};
374
375struct xattr_handler btrfs_xattr_trusted_handler = {
3acd7ee8 376 .prefix = XATTR_TRUSTED_PREFIX,
5103e947
JB
377 .get = btrfs_xattr_trusted_get,
378 .set = btrfs_xattr_trusted_set,
379};