aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/gfs2/bmap.c2
-rw-r--r--fs/gfs2/dir.c144
-rw-r--r--fs/gfs2/dir.h4
3 files changed, 78 insertions, 72 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index c7723119acb6..68bc3be09c98 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -111,7 +111,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer,
111 if (isdir) { 111 if (isdir) {
112 block = gfs2_alloc_meta(ip); 112 block = gfs2_alloc_meta(ip);
113 113
114 error = gfs2_dir_get_buffer(ip, block, 1, &bh); 114 error = gfs2_dir_get_new_buffer(ip, block, &bh);
115 if (error) 115 if (error)
116 goto out_brelse; 116 goto out_brelse;
117 gfs2_buffer_copy_tail(bh, 117 gfs2_buffer_copy_tail(bh,
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index eb68cdd41d48..ffc1beff6703 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -8,61 +8,59 @@
8 */ 8 */
9 9
10/* 10/*
11* Implements Extendible Hashing as described in: 11 * Implements Extendible Hashing as described in:
12* "Extendible Hashing" by Fagin, et al in 12 * "Extendible Hashing" by Fagin, et al in
13* __ACM Trans. on Database Systems__, Sept 1979. 13 * __ACM Trans. on Database Systems__, Sept 1979.
14* 14 *
15* 15 *
16* Here's the layout of dirents which is essentially the same as that of ext2 16 * Here's the layout of dirents which is essentially the same as that of ext2
17* within a single block. The field de_name_len is the number of bytes 17 * within a single block. The field de_name_len is the number of bytes
18* actually required for the name (no null terminator). The field de_rec_len 18 * actually required for the name (no null terminator). The field de_rec_len
19* is the number of bytes allocated to the dirent. The offset of the next 19 * is the number of bytes allocated to the dirent. The offset of the next
20* dirent in the block is (dirent + dirent->de_rec_len). When a dirent is 20 * dirent in the block is (dirent + dirent->de_rec_len). When a dirent is
21* deleted, the preceding dirent inherits its allocated space, ie 21 * deleted, the preceding dirent inherits its allocated space, ie
22* prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained 22 * prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained
23* by adding de_rec_len to the current dirent, this essentially causes the 23 * by adding de_rec_len to the current dirent, this essentially causes the
24* deleted dirent to get jumped over when iterating through all the dirents. 24 * deleted dirent to get jumped over when iterating through all the dirents.
25* 25 *
26* When deleting the first dirent in a block, there is no previous dirent so 26 * When deleting the first dirent in a block, there is no previous dirent so
27* the field de_ino is set to zero to designate it as deleted. When allocating 27 * the field de_ino is set to zero to designate it as deleted. When allocating
28* a dirent, gfs2_dirent_alloc iterates through the dirents in a block. If the 28 * a dirent, gfs2_dirent_alloc iterates through the dirents in a block. If the
29* first dirent has (de_ino == 0) and de_rec_len is large enough, this first 29 * first dirent has (de_ino == 0) and de_rec_len is large enough, this first
30* dirent is allocated. Otherwise it must go through all the 'used' dirents 30 * dirent is allocated. Otherwise it must go through all the 'used' dirents
31* searching for one in which the amount of total space minus the amount of 31 * searching for one in which the amount of total space minus the amount of
32* used space will provide enough space for the new dirent. 32 * used space will provide enough space for the new dirent.
33* 33 *
34* There are two types of blocks in which dirents reside. In a stuffed dinode, 34 * There are two types of blocks in which dirents reside. In a stuffed dinode,
35* the dirents begin at offset sizeof(struct gfs2_dinode) from the beginning of 35 * the dirents begin at offset sizeof(struct gfs2_dinode) from the beginning of
36* the block. In leaves, they begin at offset sizeof(struct gfs2_leaf) from the 36 * the block. In leaves, they begin at offset sizeof(struct gfs2_leaf) from the
37* beginning of the leaf block. The dirents reside in leaves when 37 * beginning of the leaf block. The dirents reside in leaves when
38* 38 *
39* dip->i_di.di_flags & GFS2_DIF_EXHASH is true 39 * dip->i_di.di_flags & GFS2_DIF_EXHASH is true
40* 40 *
41* Otherwise, the dirents are "linear", within a single stuffed dinode block. 41 * Otherwise, the dirents are "linear", within a single stuffed dinode block.
42* 42 *
43* When the dirents are in leaves, the actual contents of the directory file are 43 * When the dirents are in leaves, the actual contents of the directory file are
44* used as an array of 64-bit block pointers pointing to the leaf blocks. The 44 * used as an array of 64-bit block pointers pointing to the leaf blocks. The
45* dirents are NOT in the directory file itself. There can be more than one block 45 * dirents are NOT in the directory file itself. There can be more than one
46* pointer in the array that points to the same leaf. In fact, when a directory 46 * block pointer in the array that points to the same leaf. In fact, when a
47* is first converted from linear to exhash, all of the pointers point to the 47 * directory is first converted from linear to exhash, all of the pointers
48* same leaf. 48 * point to the same leaf.
49* 49 *
50* When a leaf is completely full, the size of the hash table can be 50 * When a leaf is completely full, the size of the hash table can be
51* doubled unless it is already at the maximum size which is hard coded into 51 * doubled unless it is already at the maximum size which is hard coded into
52* GFS2_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list, 52 * GFS2_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list,
53* but never before the maximum hash table size has been reached. 53 * but never before the maximum hash table size has been reached.
54*/ 54 */
55 55
56#include <linux/sched.h> 56#include <linux/sched.h>
57#include <linux/slab.h> 57#include <linux/slab.h>
58#include <linux/spinlock.h> 58#include <linux/spinlock.h>
59#include <linux/completion.h>
60#include <linux/buffer_head.h> 59#include <linux/buffer_head.h>
61#include <linux/sort.h> 60#include <linux/sort.h>
62#include <linux/gfs2_ondisk.h> 61#include <linux/gfs2_ondisk.h>
63#include <linux/crc32.h> 62#include <linux/crc32.h>
64#include <linux/vmalloc.h> 63#include <linux/vmalloc.h>
65#include <asm/semaphore.h>
66 64
67#include "gfs2.h" 65#include "gfs2.h"
68#include "lm_interface.h" 66#include "lm_interface.h"
@@ -92,33 +90,36 @@ typedef int (*leaf_call_t) (struct gfs2_inode *dip,
92 uint32_t index, uint32_t len, uint64_t leaf_no, 90 uint32_t index, uint32_t len, uint64_t leaf_no,
93 void *data); 91 void *data);
94 92
95int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, 93
96 struct buffer_head **bhp) 94int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block,
95 struct buffer_head **bhp)
97{ 96{
98 struct buffer_head *bh; 97 struct buffer_head *bh;
99 int error = 0;
100
101 if (new) {
102 bh = gfs2_meta_new(ip->i_gl, block);
103 gfs2_trans_add_bh(ip->i_gl, bh, 1);
104 gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD);
105 gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
106 } else {
107 error = gfs2_meta_read(ip->i_gl, block, DIO_START | DIO_WAIT,
108 &bh);
109 if (error)
110 return error;
111 if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_JD)) {
112 brelse(bh);
113 return -EIO;
114 }
115 }
116 98
99 bh = gfs2_meta_new(ip->i_gl, block);
100 gfs2_trans_add_bh(ip->i_gl, bh, 1);
101 gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD);
102 gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
117 *bhp = bh; 103 *bhp = bh;
118 return 0; 104 return 0;
119} 105}
120 106
107static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, uint64_t block,
108 struct buffer_head **bhp)
109{
110 struct buffer_head *bh;
111 int error;
121 112
113 error = gfs2_meta_read(ip->i_gl, block, DIO_START | DIO_WAIT, &bh);
114 if (error)
115 return error;
116 if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_JD)) {
117 brelse(bh);
118 return -EIO;
119 }
120 *bhp = bh;
121 return 0;
122}
122 123
123static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, 124static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
124 unsigned int offset, unsigned int size) 125 unsigned int offset, unsigned int size)
@@ -205,9 +206,11 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
205 goto fail; 206 goto fail;
206 } 207 }
207 208
208 error = gfs2_dir_get_buffer(ip, dblock, 209 if (amount == sdp->sd_jbsize || new)
209 (amount == sdp->sd_jbsize) ? 210 error = gfs2_dir_get_new_buffer(ip, dblock, &bh);
210 1 : new, &bh); 211 else
212 error = gfs2_dir_get_existing_buffer(ip, dblock, &bh);
213
211 if (error) 214 if (error)
212 goto fail; 215 goto fail;
213 216
@@ -321,7 +324,10 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf,
321 gfs2_meta_ra(ip->i_gl, dblock, extlen); 324 gfs2_meta_ra(ip->i_gl, dblock, extlen);
322 325
323 if (dblock) { 326 if (dblock) {
324 error = gfs2_dir_get_buffer(ip, dblock, new, &bh); 327 if (new)
328 error = gfs2_dir_get_new_buffer(ip, dblock, &bh);
329 else
330 error = gfs2_dir_get_existing_buffer(ip, dblock, &bh);
325 if (error) 331 if (error)
326 goto fail; 332 goto fail;
327 dblock++; 333 dblock++;
diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
index 42b3a1f34deb..d209f1fcb8ac 100644
--- a/fs/gfs2/dir.h
+++ b/fs/gfs2/dir.h
@@ -41,8 +41,8 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip);
41 41
42int gfs2_diradd_alloc_required(struct inode *dir, 42int gfs2_diradd_alloc_required(struct inode *dir,
43 const struct qstr *filename); 43 const struct qstr *filename);
44int gfs2_dir_get_buffer(struct gfs2_inode *ip, uint64_t block, int new, 44int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, uint64_t block,
45 struct buffer_head **bhp); 45 struct buffer_head **bhp);
46 46
47static inline uint32_t gfs2_disk_hash(const char *data, int len) 47static inline uint32_t gfs2_disk_hash(const char *data, int len)
48{ 48{