aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/dir-item.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/dir-item.c')
-rw-r--r--fs/btrfs/dir-item.c74
1 files changed, 69 insertions, 5 deletions
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index 62d0c0916a73..b1629a5d73c8 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -4,6 +4,26 @@
4#include "hash.h" 4#include "hash.h"
5#include "transaction.h" 5#include "transaction.h"
6 6
7int insert_with_overflow(struct btrfs_trans_handle *trans, struct btrfs_root
8 *root, struct btrfs_path *path, struct btrfs_key
9 *cpu_key, u32 data_size)
10{
11 int overflow;
12 int ret;
13
14 ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
15 overflow = btrfs_key_overflow(cpu_key);
16
17 while(ret == -EEXIST && overflow < BTRFS_KEY_OVERFLOW_MAX) {
18 overflow++;
19 btrfs_set_key_overflow(cpu_key, overflow);
20 btrfs_release_path(root, path);
21 ret = btrfs_insert_empty_item(trans, root, path, cpu_key,
22 data_size);
23 }
24 return ret;
25}
26
7int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root 27int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
8 *root, const char *name, int name_len, u64 dir, u64 28 *root, const char *name, int name_len, u64 dir, u64
9 objectid, u8 type) 29 objectid, u8 type)
@@ -23,7 +43,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
23 path = btrfs_alloc_path(); 43 path = btrfs_alloc_path();
24 btrfs_init_path(path); 44 btrfs_init_path(path);
25 data_size = sizeof(*dir_item) + name_len; 45 data_size = sizeof(*dir_item) + name_len;
26 ret = btrfs_insert_empty_item(trans, root, path, &key, data_size); 46 ret = insert_with_overflow(trans, root, path, &key, data_size);
27 if (ret) 47 if (ret)
28 goto out; 48 goto out;
29 49
@@ -41,7 +61,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
41 61
42 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); 62 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
43 key.offset = objectid; 63 key.offset = objectid;
44 ret = btrfs_insert_empty_item(trans, root, path, &key, data_size); 64 ret = insert_with_overflow(trans, root, path, &key, data_size);
45 // FIXME clear the dirindex bit 65 // FIXME clear the dirindex bit
46 if (ret) 66 if (ret)
47 goto out; 67 goto out;
@@ -70,14 +90,40 @@ int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
70 struct btrfs_key key; 90 struct btrfs_key key;
71 int ins_len = mod < 0 ? -1 : 0; 91 int ins_len = mod < 0 ? -1 : 0;
72 int cow = mod != 0; 92 int cow = mod != 0;
93 struct btrfs_disk_key *found_key;
94 struct btrfs_leaf *leaf;
73 95
74 key.objectid = dir; 96 key.objectid = dir;
75 key.flags = 0; 97 key.flags = 0;
76 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); 98 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
99 btrfs_set_key_overflow(&key, BTRFS_KEY_OVERFLOW_MAX - 1);
77 ret = btrfs_name_hash(name, name_len, &key.offset); 100 ret = btrfs_name_hash(name, name_len, &key.offset);
78 BUG_ON(ret); 101 BUG_ON(ret);
79 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 102 while(1) {
80 return ret; 103 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
104 if (ret < 0)
105 return ret;
106 if (ret > 0) {
107 if (path->slots[0] == 0)
108 return 1;
109 path->slots[0]--;
110 }
111 leaf = btrfs_buffer_leaf(path->nodes[0]);
112 found_key = &leaf->items[path->slots[0]].key;
113
114 if (btrfs_disk_key_objectid(found_key) != dir ||
115 btrfs_disk_key_type(found_key) != BTRFS_DIR_ITEM_KEY ||
116 btrfs_disk_key_offset(found_key) != key.offset)
117 return 1;
118
119 if (btrfs_match_dir_item_name(root, path, name, name_len))
120 return 0;
121
122 if (btrfs_disk_key_overflow(found_key) == 0)
123 return 1;
124 btrfs_release_path(root, path);
125 }
126 return 1;
81} 127}
82 128
83int btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, 129int btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
@@ -89,13 +135,31 @@ int btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
89 struct btrfs_key key; 135 struct btrfs_key key;
90 int ins_len = mod < 0 ? -1 : 0; 136 int ins_len = mod < 0 ? -1 : 0;
91 int cow = mod != 0; 137 int cow = mod != 0;
138 struct btrfs_disk_key *found_key;
139 struct btrfs_leaf *leaf;
92 140
93 key.objectid = dir; 141 key.objectid = dir;
94 key.flags = 0; 142 key.flags = 0;
95 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); 143 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
144 btrfs_set_key_overflow(&key, BTRFS_KEY_OVERFLOW_MAX - 1);
96 key.offset = objectid; 145 key.offset = objectid;
97 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 146 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
98 return ret; 147 if (ret < 0)
148 return ret;
149 if (ret > 0) {
150 if (path->slots[0] == 0)
151 return 1;
152 path->slots[0]--;
153 }
154 leaf = btrfs_buffer_leaf(path->nodes[0]);
155 found_key = &leaf->items[path->slots[0]].key;
156
157 if (btrfs_disk_key_objectid(found_key) != dir ||
158 btrfs_disk_key_type(found_key) != BTRFS_DIR_INDEX_KEY)
159 return 1;
160 if (btrfs_disk_key_offset(found_key) == objectid)
161 return 0;
162 return 1;
99} 163}
100 164
101int btrfs_match_dir_item_name(struct btrfs_root *root, 165int btrfs_match_dir_item_name(struct btrfs_root *root,