Blame view

fs/btrfs/dir-item.c 14.5 KB
6cbd55707   Chris Mason   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   Chris Mason   Btrfs: Use a chun...
18
19
20
  #include "ctree.h"
  #include "disk-io.h"
  #include "hash.h"
e089f05c1   Chris Mason   Btrfs: transactio...
21
  #include "transaction.h"
62e2749e0   Chris Mason   Btrfs: Use a chun...
22

d352ac681   Chris Mason   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   Chris Mason   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   Chris Mason   Btrfs: rename
36
37
38
  						   u32 data_size,
  						   const char *name,
  						   int name_len)
7fcde0e32   Chris Mason   Btrfs: finish off...
39
  {
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
40
  	struct btrfs_fs_info *fs_info = root->fs_info;
7fcde0e32   Chris Mason   Btrfs: finish off...
41
  	int ret;
7e38180e2   Chris Mason   Btrfs: directory ...
42
43
  	char *ptr;
  	struct btrfs_item *item;
5f39d397d   Chris Mason   Btrfs: Create ext...
44
  	struct extent_buffer *leaf;
7fcde0e32   Chris Mason   Btrfs: finish off...
45
46
  
  	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
7e38180e2   Chris Mason   Btrfs: directory ...
47
  	if (ret == -EEXIST) {
e06afa839   Chris Mason   Btrfs: rename
48
  		struct btrfs_dir_item *di;
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
49
  		di = btrfs_match_dir_item_name(fs_info, path, name, name_len);
e06afa839   Chris Mason   Btrfs: rename
50
51
  		if (di)
  			return ERR_PTR(-EEXIST);
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
52
  		btrfs_extend_item(fs_info, path, data_size);
143bede52   Jeff Mahoney   btrfs: return voi...
53
  	} else if (ret < 0)
54aa1f4df   Chris Mason   Btrfs: Audit call...
54
  		return ERR_PTR(ret);
7e38180e2   Chris Mason   Btrfs: directory ...
55
  	WARN_ON(ret > 0);
5f39d397d   Chris Mason   Btrfs: Create ext...
56
  	leaf = path->nodes[0];
dd3cc16b8   Ross Kirk   btrfs: drop unuse...
57
  	item = btrfs_item_nr(path->slots[0]);
7e38180e2   Chris Mason   Btrfs: directory ...
58
  	ptr = btrfs_item_ptr(leaf, path->slots[0], char);
5f39d397d   Chris Mason   Btrfs: Create ext...
59
60
  	BUG_ON(data_size > btrfs_item_size(leaf, item));
  	ptr += btrfs_item_size(leaf, item) - data_size;
7e38180e2   Chris Mason   Btrfs: directory ...
61
  	return (struct btrfs_dir_item *)ptr;
7fcde0e32   Chris Mason   Btrfs: finish off...
62
  }
d352ac681   Chris Mason   Btrfs: add and im...
63
64
65
66
  /*
   * xattrs work a lot like directories, this inserts an xattr item
   * into the tree
   */
5103e947b   Josef Bacik   xattr support for...
67
  int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
f34f57a3a   Yan, Zheng   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   Josef Bacik   xattr support for...
72
73
  {
  	int ret = 0;
5103e947b   Josef Bacik   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;
b9d04c607   David Sterba   btrfs: do proper ...
80
81
  	if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info))
  		return -ENOSPC;
f34f57a3a   Yan, Zheng   Btrfs: Pass trans...
82
83
  
  	key.objectid = objectid;
962a298f3   David Sterba   btrfs: kill the k...
84
  	key.type = BTRFS_XATTR_ITEM_KEY;
df68b8a7a   David Miller   Btrfs: unaligned ...
85
  	key.offset = btrfs_name_hash(name, name_len);
5103e947b   Josef Bacik   xattr support for...
86
87
88
89
  
  	data_size = sizeof(*dir_item) + name_len + data_len;
  	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
  					name, name_len);
fa09200b8   Josef Bacik   Btrfs: try to onl...
90
91
  	if (IS_ERR(dir_item))
  		return PTR_ERR(dir_item);
5103e947b   Josef Bacik   xattr support for...
92
93
94
95
96
97
98
  	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   Chris Mason   Btrfs: Add a writ...
99
  	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
5103e947b   Josef Bacik   xattr support for...
100
101
102
103
104
105
106
  	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   Josef Bacik   xattr support for...
107
108
  	return ret;
  }
d352ac681   Chris Mason   Btrfs: add and im...
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).
79787eaab   Jeff Mahoney   btrfs: replace ma...
115
   * Will return 0 or -ENOMEM
d352ac681   Chris Mason   Btrfs: add and im...
116
   */
e089f05c1   Chris Mason   Btrfs: transactio...
117
  int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
16cdcec73   Miao Xie   btrfs: implement ...
118
  			  *root, const char *name, int name_len,
8e7611cf3   Nikolay Borisov   btrfs: Make btrfs...
119
  			  struct btrfs_inode *dir, struct btrfs_key *location,
16cdcec73   Miao Xie   btrfs: implement ...
120
  			  u8 type, u64 index)
62e2749e0   Chris Mason   Btrfs: Use a chun...
121
122
  {
  	int ret = 0;
e06afa839   Chris Mason   Btrfs: rename
123
  	int ret2 = 0;
5caf2a002   Chris Mason   Btrfs: dynamic al...
124
  	struct btrfs_path *path;
62e2749e0   Chris Mason   Btrfs: Use a chun...
125
  	struct btrfs_dir_item *dir_item;
5f39d397d   Chris Mason   Btrfs: Create ext...
126
127
  	struct extent_buffer *leaf;
  	unsigned long name_ptr;
62e2749e0   Chris Mason   Btrfs: Use a chun...
128
  	struct btrfs_key key;
5f39d397d   Chris Mason   Btrfs: Create ext...
129
  	struct btrfs_disk_key disk_key;
62e2749e0   Chris Mason   Btrfs: Use a chun...
130
  	u32 data_size;
8e7611cf3   Nikolay Borisov   btrfs: Make btrfs...
131
  	key.objectid = btrfs_ino(dir);
962a298f3   David Sterba   btrfs: kill the k...
132
  	key.type = BTRFS_DIR_ITEM_KEY;
df68b8a7a   David Miller   Btrfs: unaligned ...
133
  	key.offset = btrfs_name_hash(name, name_len);
b9473439d   Chris Mason   Btrfs: leave btre...
134

5caf2a002   Chris Mason   Btrfs: dynamic al...
135
  	path = btrfs_alloc_path();
16cdcec73   Miao Xie   btrfs: implement ...
136
137
  	if (!path)
  		return -ENOMEM;
b9473439d   Chris Mason   Btrfs: leave btre...
138
  	path->leave_spinning = 1;
16cdcec73   Miao Xie   btrfs: implement ...
139
  	btrfs_cpu_key_to_disk(&disk_key, location);
62e2749e0   Chris Mason   Btrfs: Use a chun...
140
  	data_size = sizeof(*dir_item) + name_len;
e06afa839   Chris Mason   Btrfs: rename
141
142
  	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
  					name, name_len);
7e38180e2   Chris Mason   Btrfs: directory ...
143
144
  	if (IS_ERR(dir_item)) {
  		ret = PTR_ERR(dir_item);
e06afa839   Chris Mason   Btrfs: rename
145
146
  		if (ret == -EEXIST)
  			goto second_insert;
c2db1073f   Tsutomu Itoh   Btrfs: check retu...
147
  		goto out_free;
7e38180e2   Chris Mason   Btrfs: directory ...
148
  	}
62e2749e0   Chris Mason   Btrfs: Use a chun...
149

5f39d397d   Chris Mason   Btrfs: Create ext...
150
  	leaf = path->nodes[0];
5f39d397d   Chris Mason   Btrfs: Create ext...
151
152
  	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
  	btrfs_set_dir_type(leaf, dir_item, type);
5103e947b   Josef Bacik   xattr support for...
153
  	btrfs_set_dir_data_len(leaf, dir_item, 0);
5f39d397d   Chris Mason   Btrfs: Create ext...
154
  	btrfs_set_dir_name_len(leaf, dir_item, name_len);
e02119d5a   Chris Mason   Btrfs: Add a writ...
155
  	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
5f39d397d   Chris Mason   Btrfs: Create ext...
156
  	name_ptr = (unsigned long)(dir_item + 1);
c5739bba5   Chris Mason   Btrfs: snapshot p...
157

5f39d397d   Chris Mason   Btrfs: Create ext...
158
159
  	write_extent_buffer(leaf, name, name_ptr, name_len);
  	btrfs_mark_buffer_dirty(leaf);
7e38180e2   Chris Mason   Btrfs: directory ...
160

e06afa839   Chris Mason   Btrfs: rename
161
  second_insert:
7e38180e2   Chris Mason   Btrfs: directory ...
162
163
164
  	/* FIXME, use some real flag for selecting the extra index */
  	if (root == root->fs_info->tree_root) {
  		ret = 0;
c2db1073f   Tsutomu Itoh   Btrfs: check retu...
165
  		goto out_free;
7e38180e2   Chris Mason   Btrfs: directory ...
166
  	}
b3b4aa74b   David Sterba   btrfs: drop unuse...
167
  	btrfs_release_path(path);
7e38180e2   Chris Mason   Btrfs: directory ...
168

2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
169
  	ret2 = btrfs_insert_delayed_dir_index(trans, root->fs_info, name,
8e7611cf3   Nikolay Borisov   btrfs: Make btrfs...
170
  			name_len, dir, &disk_key, type, index);
c2db1073f   Tsutomu Itoh   Btrfs: check retu...
171
  out_free:
5caf2a002   Chris Mason   Btrfs: dynamic al...
172
  	btrfs_free_path(path);
e06afa839   Chris Mason   Btrfs: rename
173
174
175
176
177
  	if (ret)
  		return ret;
  	if (ret2)
  		return ret2;
  	return 0;
62e2749e0   Chris Mason   Btrfs: Use a chun...
178
  }
d352ac681   Chris Mason   Btrfs: add and im...
179
180
181
182
183
  /*
   * 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   Chris Mason   Btrfs: directory ...
184
185
186
187
188
  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   Chris Mason   Btrfs: Use a chun...
189
  {
1d4f6404d   Chris Mason   Btrfs: directory ...
190
  	int ret;
62e2749e0   Chris Mason   Btrfs: Use a chun...
191
  	struct btrfs_key key;
1d4f6404d   Chris Mason   Btrfs: directory ...
192
193
  	int ins_len = mod < 0 ? -1 : 0;
  	int cow = mod != 0;
62e2749e0   Chris Mason   Btrfs: Use a chun...
194
195
  
  	key.objectid = dir;
962a298f3   David Sterba   btrfs: kill the k...
196
  	key.type = BTRFS_DIR_ITEM_KEY;
5f39d397d   Chris Mason   Btrfs: Create ext...
197

df68b8a7a   David Miller   Btrfs: unaligned ...
198
  	key.offset = btrfs_name_hash(name, name_len);
5f39d397d   Chris Mason   Btrfs: Create ext...
199

7e38180e2   Chris Mason   Btrfs: directory ...
200
201
202
  	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
  	if (ret < 0)
  		return ERR_PTR(ret);
85d85a743   Li Zefan   Btrfs: remove red...
203
  	if (ret > 0)
7e38180e2   Chris Mason   Btrfs: directory ...
204
  		return NULL;
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
205
  	return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
62e2749e0   Chris Mason   Btrfs: Use a chun...
206
  }
9c52057c6   Chris Mason   Btrfs: fix hash o...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
  				   const char *name, int name_len)
  {
  	int ret;
  	struct btrfs_key key;
  	struct btrfs_dir_item *di;
  	int data_size;
  	struct extent_buffer *leaf;
  	int slot;
  	struct btrfs_path *path;
  
  
  	path = btrfs_alloc_path();
  	if (!path)
  		return -ENOMEM;
  
  	key.objectid = dir;
962a298f3   David Sterba   btrfs: kill the k...
224
  	key.type = BTRFS_DIR_ITEM_KEY;
9c52057c6   Chris Mason   Btrfs: fix hash o...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  	key.offset = btrfs_name_hash(name, name_len);
  
  	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
  
  	/* return back any errors */
  	if (ret < 0)
  		goto out;
  
  	/* nothing found, we're safe */
  	if (ret > 0) {
  		ret = 0;
  		goto out;
  	}
  
  	/* we found an item, look for our name in the item */
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
240
  	di = btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
9c52057c6   Chris Mason   Btrfs: fix hash o...
241
242
243
244
245
246
247
248
249
250
  	if (di) {
  		/* our exact name was found */
  		ret = -EEXIST;
  		goto out;
  	}
  
  	/*
  	 * see if there is room in the item to insert this
  	 * name
  	 */
878f2d2cb   Filipe David Borba Manana   Btrfs: fix max di...
251
  	data_size = sizeof(*di) + name_len;
9c52057c6   Chris Mason   Btrfs: fix hash o...
252
253
254
  	leaf = path->nodes[0];
  	slot = path->slots[0];
  	if (data_size + btrfs_item_size_nr(leaf, slot) +
da17066c4   Jeff Mahoney   btrfs: pull node/...
255
  	    sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
9c52057c6   Chris Mason   Btrfs: fix hash o...
256
257
258
259
260
261
262
263
264
  		ret = -EOVERFLOW;
  	} else {
  		/* plenty of insertion room */
  		ret = 0;
  	}
  out:
  	btrfs_free_path(path);
  	return ret;
  }
d352ac681   Chris Mason   Btrfs: add and im...
265
266
267
268
269
270
271
272
  /*
   * 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   Chris Mason   Btrfs: directory ...
273
274
275
276
277
278
279
280
281
282
283
284
285
  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;
962a298f3   David Sterba   btrfs: kill the k...
286
  	key.type = BTRFS_DIR_INDEX_KEY;
7e38180e2   Chris Mason   Btrfs: directory ...
287
288
289
290
291
292
293
  	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);
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
294
  	return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
7e38180e2   Chris Mason   Btrfs: directory ...
295
  }
4df27c4d5   Yan, Zheng   Btrfs: change how...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  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;
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
333
334
  		di = btrfs_match_dir_item_name(root->fs_info, path,
  					       name, name_len);
4df27c4d5   Yan, Zheng   Btrfs: change how...
335
336
337
338
339
340
341
  		if (di)
  			return di;
  
  		path->slots[0]++;
  	}
  	return NULL;
  }
5103e947b   Josef Bacik   xattr support for...
342
343
344
345
346
347
348
349
350
351
  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   Josef Bacik   xattr support for...
352
353
  
  	key.objectid = dir;
962a298f3   David Sterba   btrfs: kill the k...
354
  	key.type = BTRFS_XATTR_ITEM_KEY;
df68b8a7a   David Miller   Btrfs: unaligned ...
355
  	key.offset = btrfs_name_hash(name, name_len);
5103e947b   Josef Bacik   xattr support for...
356
357
358
  	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
  	if (ret < 0)
  		return ERR_PTR(ret);
85d85a743   Li Zefan   Btrfs: remove red...
359
  	if (ret > 0)
5103e947b   Josef Bacik   xattr support for...
360
  		return NULL;
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
361
  	return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
5103e947b   Josef Bacik   xattr support for...
362
  }
d352ac681   Chris Mason   Btrfs: add and im...
363
364
365
366
367
  /*
   * 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.
   */
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
368
  struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
5f5bc6b1e   Filipe Manana   Btrfs: make xattr...
369
370
  						 struct btrfs_path *path,
  						 const char *name, int name_len)
62e2749e0   Chris Mason   Btrfs: Use a chun...
371
  {
62e2749e0   Chris Mason   Btrfs: Use a chun...
372
  	struct btrfs_dir_item *dir_item;
5f39d397d   Chris Mason   Btrfs: Create ext...
373
  	unsigned long name_ptr;
7e38180e2   Chris Mason   Btrfs: directory ...
374
375
376
  	u32 total_len;
  	u32 cur = 0;
  	u32 this_len;
5f39d397d   Chris Mason   Btrfs: Create ext...
377
  	struct extent_buffer *leaf;
a8a2ee0c6   Chris Mason   Btrfs: add a name...
378

5f39d397d   Chris Mason   Btrfs: Create ext...
379
  	leaf = path->nodes[0];
7e38180e2   Chris Mason   Btrfs: directory ...
380
  	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
22a94d44b   Josef Bacik   Btrfs: add checks...
381

5f39d397d   Chris Mason   Btrfs: Create ext...
382
  	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
d397712bc   Chris Mason   Btrfs: Fix checkp...
383
  	while (cur < total_len) {
5f39d397d   Chris Mason   Btrfs: Create ext...
384
  		this_len = sizeof(*dir_item) +
5103e947b   Josef Bacik   xattr support for...
385
386
  			btrfs_dir_name_len(leaf, dir_item) +
  			btrfs_dir_data_len(leaf, dir_item);
5f39d397d   Chris Mason   Btrfs: Create ext...
387
  		name_ptr = (unsigned long)(dir_item + 1);
7e38180e2   Chris Mason   Btrfs: directory ...
388

26a836cec   Su Yue   btrfs: Check name...
389
390
  		if (verify_dir_item(fs_info, leaf, path->slots[0], dir_item))
  			return NULL;
5f39d397d   Chris Mason   Btrfs: Create ext...
391
392
  		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
  		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
7e38180e2   Chris Mason   Btrfs: directory ...
393
394
395
396
397
398
399
  			return dir_item;
  
  		cur += this_len;
  		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
  						     this_len);
  	}
  	return NULL;
62e2749e0   Chris Mason   Btrfs: Use a chun...
400
  }
7e38180e2   Chris Mason   Btrfs: directory ...
401

d352ac681   Chris Mason   Btrfs: add and im...
402
403
404
405
  /*
   * given a pointer into a directory item, delete it.  This
   * handles items that have more than one entry in them.
   */
7e38180e2   Chris Mason   Btrfs: directory ...
406
407
408
409
410
  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   Chris Mason   Btrfs: Create ext...
411
  	struct extent_buffer *leaf;
7e38180e2   Chris Mason   Btrfs: directory ...
412
413
  	u32 sub_item_len;
  	u32 item_len;
54aa1f4df   Chris Mason   Btrfs: Audit call...
414
  	int ret = 0;
7e38180e2   Chris Mason   Btrfs: directory ...
415

5f39d397d   Chris Mason   Btrfs: Create ext...
416
  	leaf = path->nodes[0];
5103e947b   Josef Bacik   xattr support for...
417
418
  	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
  		btrfs_dir_data_len(leaf, di);
5f39d397d   Chris Mason   Btrfs: Create ext...
419
420
  	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
  	if (sub_item_len == item_len) {
7e38180e2   Chris Mason   Btrfs: directory ...
421
  		ret = btrfs_del_item(trans, root, path);
7e38180e2   Chris Mason   Btrfs: directory ...
422
  	} else {
5f39d397d   Chris Mason   Btrfs: Create ext...
423
424
425
426
427
428
  		/* 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   Chris Mason   Btrfs: directory ...
429
  			item_len - (ptr + sub_item_len - start));
2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
430
431
  		btrfs_truncate_item(root->fs_info, path,
  				    item_len - sub_item_len, 1);
7e38180e2   Chris Mason   Btrfs: directory ...
432
  	}
411fc6bce   Andi Kleen   Btrfs: Fix variab...
433
  	return ret;
7e38180e2   Chris Mason   Btrfs: directory ...
434
  }
22a94d44b   Josef Bacik   Btrfs: add checks...
435

2ff7e61e0   Jeff Mahoney   btrfs: take an fs...
436
  int verify_dir_item(struct btrfs_fs_info *fs_info,
22a94d44b   Josef Bacik   Btrfs: add checks...
437
  		    struct extent_buffer *leaf,
e79a33270   Su Yue   btrfs: Check name...
438
  		    int slot,
22a94d44b   Josef Bacik   Btrfs: add checks...
439
440
441
  		    struct btrfs_dir_item *dir_item)
  {
  	u16 namelen = BTRFS_NAME_LEN;
e79a33270   Su Yue   btrfs: Check name...
442
  	int ret;
22a94d44b   Josef Bacik   Btrfs: add checks...
443
444
445
  	u8 type = btrfs_dir_type(leaf, dir_item);
  
  	if (type >= BTRFS_FT_MAX) {
0b246afa6   Jeff Mahoney   btrfs: root->fs_i...
446
  		btrfs_crit(fs_info, "invalid dir item type: %d", (int)type);
22a94d44b   Josef Bacik   Btrfs: add checks...
447
448
449
450
451
452
453
  		return 1;
  	}
  
  	if (type == BTRFS_FT_XATTR)
  		namelen = XATTR_NAME_MAX;
  
  	if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
0b246afa6   Jeff Mahoney   btrfs: root->fs_i...
454
  		btrfs_crit(fs_info, "invalid dir item name len: %u",
286b92f43   Su Yue   btrfs: tree-log.c...
455
  		       (unsigned)btrfs_dir_name_len(leaf, dir_item));
22a94d44b   Josef Bacik   Btrfs: add checks...
456
457
  		return 1;
  	}
e79a33270   Su Yue   btrfs: Check name...
458
459
460
461
462
  	namelen = btrfs_dir_name_len(leaf, dir_item);
  	ret = btrfs_is_name_len_valid(leaf, slot,
  				      (unsigned long)(dir_item + 1), namelen);
  	if (!ret)
  		return 1;
22a94d44b   Josef Bacik   Btrfs: add checks...
463
  	/* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
e46f5388c   Filipe David Borba Manana   Btrfs: fix verifi...
464
  	if ((btrfs_dir_data_len(leaf, dir_item) +
0b246afa6   Jeff Mahoney   btrfs: root->fs_i...
465
466
467
  	     btrfs_dir_name_len(leaf, dir_item)) >
  					BTRFS_MAX_XATTR_SIZE(fs_info)) {
  		btrfs_crit(fs_info, "invalid dir item name + data len: %u + %u",
5d163e0e6   Jeff Mahoney   btrfs: unsplit pr...
468
469
  			   (unsigned)btrfs_dir_name_len(leaf, dir_item),
  			   (unsigned)btrfs_dir_data_len(leaf, dir_item));
22a94d44b   Josef Bacik   Btrfs: add checks...
470
471
472
473
474
  		return 1;
  	}
  
  	return 0;
  }
19c6dcbfa   Su Yue   btrfs: Introduce ...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  
  bool btrfs_is_name_len_valid(struct extent_buffer *leaf, int slot,
  			     unsigned long start, u16 name_len)
  {
  	struct btrfs_fs_info *fs_info = leaf->fs_info;
  	struct btrfs_key key;
  	u32 read_start;
  	u32 read_end;
  	u32 item_start;
  	u32 item_end;
  	u32 size;
  	bool ret = true;
  
  	ASSERT(start > BTRFS_LEAF_DATA_OFFSET);
  
  	read_start = start - BTRFS_LEAF_DATA_OFFSET;
  	read_end = read_start + name_len;
  	item_start = btrfs_item_offset_nr(leaf, slot);
  	item_end = btrfs_item_end_nr(leaf, slot);
  
  	btrfs_item_key_to_cpu(leaf, &key, slot);
  
  	switch (key.type) {
  	case BTRFS_DIR_ITEM_KEY:
  	case BTRFS_XATTR_ITEM_KEY:
  	case BTRFS_DIR_INDEX_KEY:
  		size = sizeof(struct btrfs_dir_item);
  		break;
  	case BTRFS_INODE_REF_KEY:
  		size = sizeof(struct btrfs_inode_ref);
  		break;
  	case BTRFS_INODE_EXTREF_KEY:
  		size = sizeof(struct btrfs_inode_extref);
  		break;
  	case BTRFS_ROOT_REF_KEY:
  	case BTRFS_ROOT_BACKREF_KEY:
  		size = sizeof(struct btrfs_root_ref);
  		break;
  	default:
  		ret = false;
  		goto out;
  	}
  
  	if (read_start < item_start) {
  		ret = false;
  		goto out;
  	}
  	if (read_end > item_end) {
  		ret = false;
  		goto out;
  	}
  
  	/* there shall be item(s) before name */
  	if (read_start - item_start < size) {
  		ret = false;
  		goto out;
  	}
19c6dcbfa   Su Yue   btrfs: Introduce ...
532
533
534
535
536
537
  out:
  	if (!ret)
  		btrfs_crit(fs_info, "invalid dir item name len: %u",
  			   (unsigned int)name_len);
  	return ret;
  }