Blame view
fs/btrfs/dir-item.c
11.6 KB
6cbd55707 Btrfs: add GPLv2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ |
62e2749e0 Btrfs: Use a chun... |
18 19 20 |
#include "ctree.h" #include "disk-io.h" #include "hash.h" |
e089f05c1 Btrfs: transactio... |
21 |
#include "transaction.h" |
62e2749e0 Btrfs: Use a chun... |
22 |
|
d352ac681 Btrfs: add and im... |
23 24 25 26 27 28 29 30 |
/* * insert a name into a directory, doing overflow properly if there is a hash * collision. data_size indicates how big the item inserted should be. On * success a struct btrfs_dir_item pointer is returned, otherwise it is * an ERR_PTR. * * The name is not copied into the dir item, you have to do that yourself. */ |
35b7e4761 Btrfs: fix page c... |
31 32 33 34 35 |
static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *cpu_key, |
e06afa839 Btrfs: rename |
36 37 38 |
u32 data_size, const char *name, int name_len) |
7fcde0e32 Btrfs: finish off... |
39 |
{ |
7fcde0e32 Btrfs: finish off... |
40 |
int ret; |
7e38180e2 Btrfs: directory ... |
41 42 |
char *ptr; struct btrfs_item *item; |
5f39d397d Btrfs: Create ext... |
43 |
struct extent_buffer *leaf; |
7fcde0e32 Btrfs: finish off... |
44 45 |
ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); |
7e38180e2 Btrfs: directory ... |
46 |
if (ret == -EEXIST) { |
e06afa839 Btrfs: rename |
47 48 49 50 |
struct btrfs_dir_item *di; di = btrfs_match_dir_item_name(root, path, name, name_len); if (di) return ERR_PTR(-EEXIST); |
7e38180e2 Btrfs: directory ... |
51 |
ret = btrfs_extend_item(trans, root, path, data_size); |
7fcde0e32 Btrfs: finish off... |
52 |
} |
54aa1f4df Btrfs: Audit call... |
53 54 |
if (ret < 0) return ERR_PTR(ret); |
7e38180e2 Btrfs: directory ... |
55 |
WARN_ON(ret > 0); |
5f39d397d Btrfs: Create ext... |
56 57 |
leaf = path->nodes[0]; item = btrfs_item_nr(leaf, path->slots[0]); |
7e38180e2 Btrfs: directory ... |
58 |
ptr = btrfs_item_ptr(leaf, path->slots[0], char); |
5f39d397d Btrfs: Create ext... |
59 60 |
BUG_ON(data_size > btrfs_item_size(leaf, item)); ptr += btrfs_item_size(leaf, item) - data_size; |
7e38180e2 Btrfs: directory ... |
61 |
return (struct btrfs_dir_item *)ptr; |
7fcde0e32 Btrfs: finish off... |
62 |
} |
d352ac681 Btrfs: add and im... |
63 64 65 66 |
/* * xattrs work a lot like directories, this inserts an xattr item * into the tree */ |
5103e947b xattr support for... |
67 |
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, |
f34f57a3a Btrfs: Pass trans... |
68 69 70 71 |
struct btrfs_root *root, struct btrfs_path *path, u64 objectid, const char *name, u16 name_len, const void *data, u16 data_len) |
5103e947b xattr support for... |
72 73 |
{ int ret = 0; |
5103e947b xattr support for... |
74 75 76 77 78 79 |
struct btrfs_dir_item *dir_item; unsigned long name_ptr, data_ptr; struct btrfs_key key, location; struct btrfs_disk_key disk_key; struct extent_buffer *leaf; u32 data_size; |
f34f57a3a Btrfs: Pass trans... |
80 81 82 |
BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)); key.objectid = objectid; |
5103e947b xattr support for... |
83 |
btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); |
df68b8a7a Btrfs: unaligned ... |
84 |
key.offset = btrfs_name_hash(name, name_len); |
5103e947b xattr support for... |
85 86 87 88 |
data_size = sizeof(*dir_item) + name_len + data_len; dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); |
fa09200b8 Btrfs: try to onl... |
89 90 |
if (IS_ERR(dir_item)) return PTR_ERR(dir_item); |
5103e947b xattr support for... |
91 92 93 94 95 96 97 |
memset(&location, 0, sizeof(location)); leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, &location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); btrfs_set_dir_name_len(leaf, dir_item, name_len); |
e02119d5a Btrfs: Add a writ... |
98 |
btrfs_set_dir_transid(leaf, dir_item, trans->transid); |
5103e947b xattr support for... |
99 100 101 102 103 104 105 |
btrfs_set_dir_data_len(leaf, dir_item, data_len); name_ptr = (unsigned long)(dir_item + 1); data_ptr = (unsigned long)((char *)name_ptr + name_len); write_extent_buffer(leaf, name, name_ptr, name_len); write_extent_buffer(leaf, data, data_ptr, data_len); btrfs_mark_buffer_dirty(path->nodes[0]); |
5103e947b xattr support for... |
106 107 |
return ret; } |
d352ac681 Btrfs: add and im... |
108 109 110 111 112 113 114 |
/* * insert a directory item in the tree, doing all the magic for * both indexes. 'dir' indicates which objectid to insert it into, * 'location' is the key to stuff into the directory item, 'type' is the * type of the inode we're pointing to, and 'index' is the sequence number * to use for the second index (if one is created). */ |
e089f05c1 Btrfs: transactio... |
115 |
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root |
16cdcec73 btrfs: implement ... |
116 117 118 |
*root, const char *name, int name_len, struct inode *dir, struct btrfs_key *location, u8 type, u64 index) |
62e2749e0 Btrfs: Use a chun... |
119 120 |
{ int ret = 0; |
e06afa839 Btrfs: rename |
121 |
int ret2 = 0; |
5caf2a002 Btrfs: dynamic al... |
122 |
struct btrfs_path *path; |
62e2749e0 Btrfs: Use a chun... |
123 |
struct btrfs_dir_item *dir_item; |
5f39d397d Btrfs: Create ext... |
124 125 |
struct extent_buffer *leaf; unsigned long name_ptr; |
62e2749e0 Btrfs: Use a chun... |
126 |
struct btrfs_key key; |
5f39d397d Btrfs: Create ext... |
127 |
struct btrfs_disk_key disk_key; |
62e2749e0 Btrfs: Use a chun... |
128 |
u32 data_size; |
0d0ca30f1 Btrfs: update the... |
129 |
key.objectid = btrfs_ino(dir); |
1d4f6404d Btrfs: directory ... |
130 |
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); |
df68b8a7a Btrfs: unaligned ... |
131 |
key.offset = btrfs_name_hash(name, name_len); |
b9473439d Btrfs: leave btre... |
132 |
|
5caf2a002 Btrfs: dynamic al... |
133 |
path = btrfs_alloc_path(); |
16cdcec73 btrfs: implement ... |
134 135 |
if (!path) return -ENOMEM; |
b9473439d Btrfs: leave btre... |
136 |
path->leave_spinning = 1; |
16cdcec73 btrfs: implement ... |
137 |
btrfs_cpu_key_to_disk(&disk_key, location); |
62e2749e0 Btrfs: Use a chun... |
138 |
data_size = sizeof(*dir_item) + name_len; |
e06afa839 Btrfs: rename |
139 140 |
dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); |
7e38180e2 Btrfs: directory ... |
141 142 |
if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); |
e06afa839 Btrfs: rename |
143 144 |
if (ret == -EEXIST) goto second_insert; |
c2db1073f Btrfs: check retu... |
145 |
goto out_free; |
7e38180e2 Btrfs: directory ... |
146 |
} |
62e2749e0 Btrfs: Use a chun... |
147 |
|
5f39d397d Btrfs: Create ext... |
148 |
leaf = path->nodes[0]; |
5f39d397d Btrfs: Create ext... |
149 150 |
btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_type(leaf, dir_item, type); |
5103e947b xattr support for... |
151 |
btrfs_set_dir_data_len(leaf, dir_item, 0); |
5f39d397d Btrfs: Create ext... |
152 |
btrfs_set_dir_name_len(leaf, dir_item, name_len); |
e02119d5a Btrfs: Add a writ... |
153 |
btrfs_set_dir_transid(leaf, dir_item, trans->transid); |
5f39d397d Btrfs: Create ext... |
154 |
name_ptr = (unsigned long)(dir_item + 1); |
c5739bba5 Btrfs: snapshot p... |
155 |
|
5f39d397d Btrfs: Create ext... |
156 157 |
write_extent_buffer(leaf, name, name_ptr, name_len); btrfs_mark_buffer_dirty(leaf); |
7e38180e2 Btrfs: directory ... |
158 |
|
e06afa839 Btrfs: rename |
159 |
second_insert: |
7e38180e2 Btrfs: directory ... |
160 161 162 |
/* FIXME, use some real flag for selecting the extra index */ if (root == root->fs_info->tree_root) { ret = 0; |
c2db1073f Btrfs: check retu... |
163 |
goto out_free; |
7e38180e2 Btrfs: directory ... |
164 |
} |
b3b4aa74b btrfs: drop unuse... |
165 |
btrfs_release_path(path); |
7e38180e2 Btrfs: directory ... |
166 |
|
16cdcec73 btrfs: implement ... |
167 168 |
ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir, &disk_key, type, index); |
c2db1073f Btrfs: check retu... |
169 |
out_free: |
5caf2a002 Btrfs: dynamic al... |
170 |
btrfs_free_path(path); |
e06afa839 Btrfs: rename |
171 172 173 174 175 |
if (ret) return ret; if (ret2) return ret2; return 0; |
62e2749e0 Btrfs: Use a chun... |
176 |
} |
d352ac681 Btrfs: add and im... |
177 178 179 180 181 |
/* * lookup a directory item based on name. 'dir' is the objectid * we're searching in, and 'mod' tells us if you plan on deleting the * item (use mod < 0) or changing the options (use mod > 0) */ |
7e38180e2 Btrfs: directory ... |
182 183 184 185 186 |
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, const char *name, int name_len, int mod) |
62e2749e0 Btrfs: Use a chun... |
187 |
{ |
1d4f6404d Btrfs: directory ... |
188 |
int ret; |
62e2749e0 Btrfs: Use a chun... |
189 |
struct btrfs_key key; |
1d4f6404d Btrfs: directory ... |
190 191 |
int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; |
62e2749e0 Btrfs: Use a chun... |
192 193 |
key.objectid = dir; |
1d4f6404d Btrfs: directory ... |
194 |
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); |
5f39d397d Btrfs: Create ext... |
195 |
|
df68b8a7a Btrfs: unaligned ... |
196 |
key.offset = btrfs_name_hash(name, name_len); |
5f39d397d Btrfs: Create ext... |
197 |
|
7e38180e2 Btrfs: directory ... |
198 199 200 |
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); |
85d85a743 Btrfs: remove red... |
201 |
if (ret > 0) |
7e38180e2 Btrfs: directory ... |
202 203 204 |
return NULL; return btrfs_match_dir_item_name(root, path, name, name_len); |
62e2749e0 Btrfs: Use a chun... |
205 |
} |
d352ac681 Btrfs: add and im... |
206 207 208 209 210 211 212 213 |
/* * lookup a directory item based on index. 'dir' is the objectid * we're searching in, and 'mod' tells us if you plan on deleting the * item (use mod < 0) or changing the options (use mod > 0) * * The name is used to make sure the index really points to the name you were * looking for. */ |
7e38180e2 Btrfs: directory ... |
214 215 216 217 218 219 220 221 222 223 224 225 226 |
struct btrfs_dir_item * btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, u64 objectid, const char *name, int name_len, int mod) { int ret; struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; key.objectid = dir; |
7e38180e2 Btrfs: directory ... |
227 228 229 230 231 232 233 234 235 236 |
btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); key.offset = objectid; ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); if (ret > 0) return ERR_PTR(-ENOENT); return btrfs_match_dir_item_name(root, path, name, name_len); } |
4df27c4d5 Btrfs: change how... |
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
struct btrfs_dir_item * btrfs_search_dir_index_item(struct btrfs_root *root, struct btrfs_path *path, u64 dirid, const char *name, int name_len) { struct extent_buffer *leaf; struct btrfs_dir_item *di; struct btrfs_key key; u32 nritems; int ret; key.objectid = dirid; key.type = BTRFS_DIR_INDEX_KEY; key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) return ERR_PTR(ret); leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); while (1) { if (path->slots[0] >= nritems) { ret = btrfs_next_leaf(root, path); if (ret < 0) return ERR_PTR(ret); if (ret > 0) break; leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); continue; } btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY) break; di = btrfs_match_dir_item_name(root, path, name, name_len); if (di) return di; path->slots[0]++; } return NULL; } |
5103e947b xattr support for... |
283 284 285 286 287 288 289 290 291 292 |
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, const char *name, u16 name_len, int mod) { int ret; struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; |
5103e947b xattr support for... |
293 294 295 |
key.objectid = dir; btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); |
df68b8a7a Btrfs: unaligned ... |
296 |
key.offset = btrfs_name_hash(name, name_len); |
5103e947b xattr support for... |
297 298 299 |
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); |
85d85a743 Btrfs: remove red... |
300 |
if (ret > 0) |
5103e947b xattr support for... |
301 302 303 304 |
return NULL; return btrfs_match_dir_item_name(root, path, name, name_len); } |
d352ac681 Btrfs: add and im... |
305 306 307 308 309 |
/* * helper function to look at the directory item pointed to by 'path' * this walks through all the entries in a dir item and finds one * for a specific name. */ |
7e38180e2 Btrfs: directory ... |
310 |
struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, |
7f5c15160 Add generation nu... |
311 312 |
struct btrfs_path *path, const char *name, int name_len) |
62e2749e0 Btrfs: Use a chun... |
313 |
{ |
62e2749e0 Btrfs: Use a chun... |
314 |
struct btrfs_dir_item *dir_item; |
5f39d397d Btrfs: Create ext... |
315 |
unsigned long name_ptr; |
7e38180e2 Btrfs: directory ... |
316 317 318 |
u32 total_len; u32 cur = 0; u32 this_len; |
5f39d397d Btrfs: Create ext... |
319 |
struct extent_buffer *leaf; |
a8a2ee0c6 Btrfs: add a name... |
320 |
|
5f39d397d Btrfs: Create ext... |
321 |
leaf = path->nodes[0]; |
7e38180e2 Btrfs: directory ... |
322 |
dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); |
22a94d44b Btrfs: add checks... |
323 324 |
if (verify_dir_item(root, leaf, dir_item)) return NULL; |
5f39d397d Btrfs: Create ext... |
325 |
total_len = btrfs_item_size_nr(leaf, path->slots[0]); |
d397712bc Btrfs: Fix checkp... |
326 |
while (cur < total_len) { |
5f39d397d Btrfs: Create ext... |
327 |
this_len = sizeof(*dir_item) + |
5103e947b xattr support for... |
328 329 |
btrfs_dir_name_len(leaf, dir_item) + btrfs_dir_data_len(leaf, dir_item); |
5f39d397d Btrfs: Create ext... |
330 |
name_ptr = (unsigned long)(dir_item + 1); |
7e38180e2 Btrfs: directory ... |
331 |
|
5f39d397d Btrfs: Create ext... |
332 333 |
if (btrfs_dir_name_len(leaf, dir_item) == name_len && memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) |
7e38180e2 Btrfs: directory ... |
334 335 336 337 338 339 340 |
return dir_item; cur += this_len; dir_item = (struct btrfs_dir_item *)((char *)dir_item + this_len); } return NULL; |
62e2749e0 Btrfs: Use a chun... |
341 |
} |
7e38180e2 Btrfs: directory ... |
342 |
|
d352ac681 Btrfs: add and im... |
343 344 345 346 |
/* * given a pointer into a directory item, delete it. This * handles items that have more than one entry in them. */ |
7e38180e2 Btrfs: directory ... |
347 348 349 350 351 |
int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_dir_item *di) { |
5f39d397d Btrfs: Create ext... |
352 |
struct extent_buffer *leaf; |
7e38180e2 Btrfs: directory ... |
353 354 |
u32 sub_item_len; u32 item_len; |
54aa1f4df Btrfs: Audit call... |
355 |
int ret = 0; |
7e38180e2 Btrfs: directory ... |
356 |
|
5f39d397d Btrfs: Create ext... |
357 |
leaf = path->nodes[0]; |
5103e947b xattr support for... |
358 359 |
sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) + btrfs_dir_data_len(leaf, di); |
5f39d397d Btrfs: Create ext... |
360 361 |
item_len = btrfs_item_size_nr(leaf, path->slots[0]); if (sub_item_len == item_len) { |
7e38180e2 Btrfs: directory ... |
362 |
ret = btrfs_del_item(trans, root, path); |
7e38180e2 Btrfs: directory ... |
363 |
} else { |
5f39d397d Btrfs: Create ext... |
364 365 366 367 368 369 |
/* MARKER */ unsigned long ptr = (unsigned long)di; unsigned long start; start = btrfs_item_ptr_offset(leaf, path->slots[0]); memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, |
7e38180e2 Btrfs: directory ... |
370 371 |
item_len - (ptr + sub_item_len - start)); ret = btrfs_truncate_item(trans, root, path, |
179e29e48 Btrfs: Fix a numb... |
372 |
item_len - sub_item_len, 1); |
7e38180e2 Btrfs: directory ... |
373 |
} |
411fc6bce Btrfs: Fix variab... |
374 |
return ret; |
7e38180e2 Btrfs: directory ... |
375 |
} |
22a94d44b Btrfs: add checks... |
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
int verify_dir_item(struct btrfs_root *root, struct extent_buffer *leaf, struct btrfs_dir_item *dir_item) { u16 namelen = BTRFS_NAME_LEN; u8 type = btrfs_dir_type(leaf, dir_item); if (type >= BTRFS_FT_MAX) { printk(KERN_CRIT "btrfs: invalid dir item type: %d ", (int)type); return 1; } if (type == BTRFS_FT_XATTR) namelen = XATTR_NAME_MAX; if (btrfs_dir_name_len(leaf, dir_item) > namelen) { |
9694b3fcb btrfs: typo: 'btr... |
395 396 |
printk(KERN_CRIT "btrfs: invalid dir item name len: %u ", |
22a94d44b Btrfs: add checks... |
397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
(unsigned)btrfs_dir_data_len(leaf, dir_item)); return 1; } /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */ if (btrfs_dir_data_len(leaf, dir_item) > BTRFS_MAX_XATTR_SIZE(root)) { printk(KERN_CRIT "btrfs: invalid dir item data len: %u ", (unsigned)btrfs_dir_data_len(leaf, dir_item)); return 1; } return 0; } |