aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h33
-rw-r--r--fs/btrfs/dir-item.c74
-rw-r--r--fs/btrfs/super.c11
3 files changed, 107 insertions, 11 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 61d7b4738af6..794f7e4f1c07 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -270,6 +270,10 @@ struct btrfs_root {
270#define BTRFS_KEY_TYPE_MAX 256 270#define BTRFS_KEY_TYPE_MAX 256
271#define BTRFS_KEY_TYPE_MASK (BTRFS_KEY_TYPE_MAX - 1) 271#define BTRFS_KEY_TYPE_MASK (BTRFS_KEY_TYPE_MAX - 1)
272 272
273#define BTRFS_KEY_OVERFLOW_MAX 128
274#define BTRFS_KEY_OVERFLOW_SHIFT 8
275#define BTRFS_KEY_OVERFLOW_MASK (0x7FULL << BTRFS_KEY_OVERFLOW_SHIFT)
276
273/* 277/*
274 * inode items have the data typically returned from stat and store other 278 * inode items have the data typically returned from stat and store other
275 * info about object characteristics. There is one for every file and dir in 279 * info about object characteristics. There is one for every file and dir in
@@ -588,6 +592,19 @@ static inline void btrfs_set_disk_key_flags(struct btrfs_disk_key *disk,
588 disk->flags = cpu_to_le32(val); 592 disk->flags = cpu_to_le32(val);
589} 593}
590 594
595static inline u32 btrfs_key_overflow(struct btrfs_key *key)
596{
597 u32 over = key->flags & BTRFS_KEY_OVERFLOW_MASK;
598 return over >> BTRFS_KEY_OVERFLOW_SHIFT;
599}
600
601static inline void btrfs_set_key_overflow(struct btrfs_key *key, u32 over)
602{
603 BUG_ON(over > BTRFS_KEY_OVERFLOW_MAX);
604 over = over << BTRFS_KEY_OVERFLOW_SHIFT;
605 key->flags = (key->flags & ~((u64)BTRFS_KEY_OVERFLOW_MASK)) | over;
606}
607
591static inline u32 btrfs_key_type(struct btrfs_key *key) 608static inline u32 btrfs_key_type(struct btrfs_key *key)
592{ 609{
593 return key->flags & BTRFS_KEY_TYPE_MASK; 610 return key->flags & BTRFS_KEY_TYPE_MASK;
@@ -612,6 +629,22 @@ static inline void btrfs_set_disk_key_type(struct btrfs_disk_key *key, u32 type)
612 btrfs_set_disk_key_flags(key, flags); 629 btrfs_set_disk_key_flags(key, flags);
613} 630}
614 631
632static inline u32 btrfs_disk_key_overflow(struct btrfs_disk_key *key)
633{
634 u32 over = le32_to_cpu(key->flags) & BTRFS_KEY_OVERFLOW_MASK;
635 return over >> BTRFS_KEY_OVERFLOW_SHIFT;
636}
637
638static inline void btrfs_set_disK_key_overflow(struct btrfs_disk_key *key,
639 u32 over)
640{
641 u32 flags = btrfs_disk_key_flags(key);
642 BUG_ON(over > BTRFS_KEY_OVERFLOW_MAX);
643 over = over << BTRFS_KEY_OVERFLOW_SHIFT;
644 flags = (flags & ~((u64)BTRFS_KEY_OVERFLOW_MASK)) | over;
645 btrfs_set_disk_key_flags(key, flags);
646}
647
615static inline u64 btrfs_header_blocknr(struct btrfs_header *h) 648static inline u64 btrfs_header_blocknr(struct btrfs_header *h)
616{ 649{
617 return le64_to_cpu(h->blocknr); 650 return le64_to_cpu(h->blocknr);
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,
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index d776b29a1676..4fd2b168b2c4 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -486,19 +486,18 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
486 continue; 486 continue;
487 if (btrfs_disk_key_offset(&item->key) < filp->f_pos) 487 if (btrfs_disk_key_offset(&item->key) < filp->f_pos)
488 continue; 488 continue;
489 489 filp->f_pos = btrfs_disk_key_offset(&item->key);
490 advance = 1; 490 advance = 1;
491 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); 491 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
492 over = filldir(dirent, (const char *)(di + 1), 492 over = filldir(dirent, (const char *)(di + 1),
493 btrfs_dir_name_len(di), 493 btrfs_dir_name_len(di),
494 btrfs_disk_key_offset(&item->key), 494 btrfs_disk_key_offset(&item->key),
495 btrfs_dir_objectid(di), d_type); 495 btrfs_dir_objectid(di), d_type);
496 if (over) { 496 if (over)
497 filp->f_pos = btrfs_disk_key_offset(&item->key); 497 goto nopos;
498 break;
499 }
500 filp->f_pos = btrfs_disk_key_offset(&item->key) + 1;
501 } 498 }
499 filp->f_pos++;
500nopos:
502 ret = 0; 501 ret = 0;
503err: 502err:
504 btrfs_release_path(root, path); 503 btrfs_release_path(root, path);