aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/dir.c
diff options
context:
space:
mode:
authorMark Fasheh <mark.fasheh@oracle.com>2007-09-07 21:21:26 -0400
committerMark Fasheh <mark.fasheh@oracle.com>2007-10-12 14:54:36 -0400
commit316f4b9f98a353ac1be93199694fd97272378815 (patch)
treec54f7feb08fc1693f64879d8a3edc18cf3bb2713 /fs/ocfs2/dir.c
parent1d410a6e337a0d2d5543ad1d9bccb670a7a05312 (diff)
ocfs2: Move directory manipulation code into dir.c
The code for adding, removing, deleting directory entries was splattered all over namei.c. I'd rather have this all centralized, so that it's easier to make changes for inline dir data, and eventually indexed directories. None of the code in any of the functions was changed. I only removed the static keyword from some prototypes so that they could be exported. Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com> Reviewed-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2/dir.c')
-rw-r--r--fs/ocfs2/dir.c430
1 files changed, 423 insertions, 7 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 0d5fdde959c8..8e0ae022b2e9 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -55,10 +55,16 @@
55#include "journal.h" 55#include "journal.h"
56#include "namei.h" 56#include "namei.h"
57#include "suballoc.h" 57#include "suballoc.h"
58#include "super.h"
58#include "uptodate.h" 59#include "uptodate.h"
59 60
60#include "buffer_head_io.h" 61#include "buffer_head_io.h"
61 62
63#define NAMEI_RA_CHUNKS 2
64#define NAMEI_RA_BLOCKS 4
65#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
66#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
67
62static unsigned char ocfs2_filetype_table[] = { 68static unsigned char ocfs2_filetype_table[] = {
63 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK 69 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
64}; 70};
@@ -67,6 +73,347 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
67 struct inode *dir, 73 struct inode *dir,
68 struct buffer_head *parent_fe_bh, 74 struct buffer_head *parent_fe_bh,
69 struct buffer_head **new_de_bh); 75 struct buffer_head **new_de_bh);
76static int ocfs2_do_extend_dir(struct super_block *sb,
77 handle_t *handle,
78 struct inode *dir,
79 struct buffer_head *parent_fe_bh,
80 struct ocfs2_alloc_context *data_ac,
81 struct ocfs2_alloc_context *meta_ac,
82 struct buffer_head **new_bh);
83
84int ocfs2_check_dir_entry(struct inode * dir,
85 struct ocfs2_dir_entry * de,
86 struct buffer_head * bh,
87 unsigned long offset)
88{
89 const char *error_msg = NULL;
90 const int rlen = le16_to_cpu(de->rec_len);
91
92 if (rlen < OCFS2_DIR_REC_LEN(1))
93 error_msg = "rec_len is smaller than minimal";
94 else if (rlen % 4 != 0)
95 error_msg = "rec_len % 4 != 0";
96 else if (rlen < OCFS2_DIR_REC_LEN(de->name_len))
97 error_msg = "rec_len is too small for name_len";
98 else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
99 error_msg = "directory entry across blocks";
100
101 if (error_msg != NULL)
102 mlog(ML_ERROR, "bad entry in directory #%llu: %s - "
103 "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n",
104 (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg,
105 offset, (unsigned long long)le64_to_cpu(de->inode), rlen,
106 de->name_len);
107 return error_msg == NULL ? 1 : 0;
108}
109
110static inline int ocfs2_match(int len,
111 const char * const name,
112 struct ocfs2_dir_entry *de)
113{
114 if (len != de->name_len)
115 return 0;
116 if (!de->inode)
117 return 0;
118 return !memcmp(name, de->name, len);
119}
120
121/*
122 * Returns 0 if not found, -1 on failure, and 1 on success
123 */
124static int inline ocfs2_search_dirblock(struct buffer_head *bh,
125 struct inode *dir,
126 const char *name, int namelen,
127 unsigned long offset,
128 struct ocfs2_dir_entry **res_dir)
129{
130 struct ocfs2_dir_entry *de;
131 char *dlimit, *de_buf;
132 int de_len;
133 int ret = 0;
134
135 mlog_entry_void();
136
137 de_buf = bh->b_data;
138 dlimit = de_buf + dir->i_sb->s_blocksize;
139
140 while (de_buf < dlimit) {
141 /* this code is executed quadratically often */
142 /* do minimal checking `by hand' */
143
144 de = (struct ocfs2_dir_entry *) de_buf;
145
146 if (de_buf + namelen <= dlimit &&
147 ocfs2_match(namelen, name, de)) {
148 /* found a match - just to be sure, do a full check */
149 if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
150 ret = -1;
151 goto bail;
152 }
153 *res_dir = de;
154 ret = 1;
155 goto bail;
156 }
157
158 /* prevent looping on a bad block */
159 de_len = le16_to_cpu(de->rec_len);
160 if (de_len <= 0) {
161 ret = -1;
162 goto bail;
163 }
164
165 de_buf += de_len;
166 offset += de_len;
167 }
168
169bail:
170 mlog_exit(ret);
171 return ret;
172}
173
174struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
175 struct inode *dir,
176 struct ocfs2_dir_entry **res_dir)
177{
178 struct super_block *sb;
179 struct buffer_head *bh_use[NAMEI_RA_SIZE];
180 struct buffer_head *bh, *ret = NULL;
181 unsigned long start, block, b;
182 int ra_max = 0; /* Number of bh's in the readahead
183 buffer, bh_use[] */
184 int ra_ptr = 0; /* Current index into readahead
185 buffer */
186 int num = 0;
187 int nblocks, i, err;
188
189 mlog_entry_void();
190
191 *res_dir = NULL;
192 sb = dir->i_sb;
193
194 nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
195 start = OCFS2_I(dir)->ip_dir_start_lookup;
196 if (start >= nblocks)
197 start = 0;
198 block = start;
199
200restart:
201 do {
202 /*
203 * We deal with the read-ahead logic here.
204 */
205 if (ra_ptr >= ra_max) {
206 /* Refill the readahead buffer */
207 ra_ptr = 0;
208 b = block;
209 for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
210 /*
211 * Terminate if we reach the end of the
212 * directory and must wrap, or if our
213 * search has finished at this block.
214 */
215 if (b >= nblocks || (num && block == start)) {
216 bh_use[ra_max] = NULL;
217 break;
218 }
219 num++;
220
221 bh = ocfs2_bread(dir, b++, &err, 1);
222 bh_use[ra_max] = bh;
223 }
224 }
225 if ((bh = bh_use[ra_ptr++]) == NULL)
226 goto next;
227 wait_on_buffer(bh);
228 if (!buffer_uptodate(bh)) {
229 /* read error, skip block & hope for the best */
230 ocfs2_error(dir->i_sb, "reading directory %llu, "
231 "offset %lu\n",
232 (unsigned long long)OCFS2_I(dir)->ip_blkno,
233 block);
234 brelse(bh);
235 goto next;
236 }
237 i = ocfs2_search_dirblock(bh, dir, name, namelen,
238 block << sb->s_blocksize_bits,
239 res_dir);
240 if (i == 1) {
241 OCFS2_I(dir)->ip_dir_start_lookup = block;
242 ret = bh;
243 goto cleanup_and_exit;
244 } else {
245 brelse(bh);
246 if (i < 0)
247 goto cleanup_and_exit;
248 }
249 next:
250 if (++block >= nblocks)
251 block = 0;
252 } while (block != start);
253
254 /*
255 * If the directory has grown while we were searching, then
256 * search the last part of the directory before giving up.
257 */
258 block = nblocks;
259 nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
260 if (block < nblocks) {
261 start = 0;
262 goto restart;
263 }
264
265cleanup_and_exit:
266 /* Clean up the read-ahead blocks */
267 for (; ra_ptr < ra_max; ra_ptr++)
268 brelse(bh_use[ra_ptr]);
269
270 mlog_exit_ptr(ret);
271 return ret;
272}
273
274/*
275 * ocfs2_delete_entry deletes a directory entry by merging it with the
276 * previous entry
277 */
278int ocfs2_delete_entry(handle_t *handle,
279 struct inode *dir,
280 struct ocfs2_dir_entry *de_del,
281 struct buffer_head *bh)
282{
283 struct ocfs2_dir_entry *de, *pde;
284 int i, status = -ENOENT;
285
286 mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
287
288 i = 0;
289 pde = NULL;
290 de = (struct ocfs2_dir_entry *) bh->b_data;
291 while (i < bh->b_size) {
292 if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
293 status = -EIO;
294 mlog_errno(status);
295 goto bail;
296 }
297 if (de == de_del) {
298 status = ocfs2_journal_access(handle, dir, bh,
299 OCFS2_JOURNAL_ACCESS_WRITE);
300 if (status < 0) {
301 status = -EIO;
302 mlog_errno(status);
303 goto bail;
304 }
305 if (pde)
306 pde->rec_len =
307 cpu_to_le16(le16_to_cpu(pde->rec_len) +
308 le16_to_cpu(de->rec_len));
309 else
310 de->inode = 0;
311 dir->i_version++;
312 status = ocfs2_journal_dirty(handle, bh);
313 goto bail;
314 }
315 i += le16_to_cpu(de->rec_len);
316 pde = de;
317 de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len));
318 }
319bail:
320 mlog_exit(status);
321 return status;
322}
323
324/* we don't always have a dentry for what we want to add, so people
325 * like orphan dir can call this instead.
326 *
327 * If you pass me insert_bh, I'll skip the search of the other dir
328 * blocks and put the record in there.
329 */
330int __ocfs2_add_entry(handle_t *handle,
331 struct inode *dir,
332 const char *name, int namelen,
333 struct inode *inode, u64 blkno,
334 struct buffer_head *parent_fe_bh,
335 struct buffer_head *insert_bh)
336{
337 unsigned long offset;
338 unsigned short rec_len;
339 struct ocfs2_dir_entry *de, *de1;
340 struct super_block *sb;
341 int retval, status;
342
343 mlog_entry_void();
344
345 sb = dir->i_sb;
346
347 if (!namelen)
348 return -EINVAL;
349
350 rec_len = OCFS2_DIR_REC_LEN(namelen);
351 offset = 0;
352 de = (struct ocfs2_dir_entry *) insert_bh->b_data;
353 while (1) {
354 BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data);
355 /* These checks should've already been passed by the
356 * prepare function, but I guess we can leave them
357 * here anyway. */
358 if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) {
359 retval = -ENOENT;
360 goto bail;
361 }
362 if (ocfs2_match(namelen, name, de)) {
363 retval = -EEXIST;
364 goto bail;
365 }
366 if (((le64_to_cpu(de->inode) == 0) &&
367 (le16_to_cpu(de->rec_len) >= rec_len)) ||
368 (le16_to_cpu(de->rec_len) >=
369 (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
370 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
371 retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
372 if (retval < 0) {
373 mlog_errno(retval);
374 goto bail;
375 }
376
377 status = ocfs2_journal_access(handle, dir, insert_bh,
378 OCFS2_JOURNAL_ACCESS_WRITE);
379 /* By now the buffer is marked for journaling */
380 offset += le16_to_cpu(de->rec_len);
381 if (le64_to_cpu(de->inode)) {
382 de1 = (struct ocfs2_dir_entry *)((char *) de +
383 OCFS2_DIR_REC_LEN(de->name_len));
384 de1->rec_len =
385 cpu_to_le16(le16_to_cpu(de->rec_len) -
386 OCFS2_DIR_REC_LEN(de->name_len));
387 de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
388 de = de1;
389 }
390 de->file_type = OCFS2_FT_UNKNOWN;
391 if (blkno) {
392 de->inode = cpu_to_le64(blkno);
393 ocfs2_set_de_type(de, inode->i_mode);
394 } else
395 de->inode = 0;
396 de->name_len = namelen;
397 memcpy(de->name, name, namelen);
398
399 dir->i_version++;
400 status = ocfs2_journal_dirty(handle, insert_bh);
401 retval = 0;
402 goto bail;
403 }
404 offset += le16_to_cpu(de->rec_len);
405 de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
406 }
407
408 /* when you think about it, the assert above should prevent us
409 * from ever getting here. */
410 retval = -ENOSPC;
411bail:
412
413 mlog_exit(retval);
414 return retval;
415}
416
70/* 417/*
71 * ocfs2_readdir() 418 * ocfs2_readdir()
72 * 419 *
@@ -347,14 +694,83 @@ int ocfs2_empty_dir(struct inode *inode)
347 return 1; 694 return 1;
348} 695}
349 696
697int ocfs2_fill_new_dir(struct ocfs2_super *osb,
698 handle_t *handle,
699 struct inode *parent,
700 struct inode *inode,
701 struct buffer_head *fe_bh,
702 struct ocfs2_alloc_context *data_ac)
703{
704 int status;
705 struct buffer_head *new_bh = NULL;
706 struct ocfs2_dir_entry *de = NULL;
707
708 mlog_entry_void();
709
710 status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh,
711 data_ac, NULL, &new_bh);
712 if (status < 0) {
713 mlog_errno(status);
714 goto bail;
715 }
716
717 ocfs2_set_new_buffer_uptodate(inode, new_bh);
718
719 status = ocfs2_journal_access(handle, inode, new_bh,
720 OCFS2_JOURNAL_ACCESS_CREATE);
721 if (status < 0) {
722 mlog_errno(status);
723 goto bail;
724 }
725 memset(new_bh->b_data, 0, osb->sb->s_blocksize);
726
727 de = (struct ocfs2_dir_entry *) new_bh->b_data;
728 de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno);
729 de->name_len = 1;
730 de->rec_len =
731 cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
732 strcpy(de->name, ".");
733 ocfs2_set_de_type(de, S_IFDIR);
734 de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len));
735 de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno);
736 de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize -
737 OCFS2_DIR_REC_LEN(1));
738 de->name_len = 2;
739 strcpy(de->name, "..");
740 ocfs2_set_de_type(de, S_IFDIR);
741
742 status = ocfs2_journal_dirty(handle, new_bh);
743 if (status < 0) {
744 mlog_errno(status);
745 goto bail;
746 }
747
748 i_size_write(inode, inode->i_sb->s_blocksize);
749 inode->i_nlink = 2;
750 inode->i_blocks = ocfs2_inode_sector_count(inode);
751 status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
752 if (status < 0) {
753 mlog_errno(status);
754 goto bail;
755 }
756
757 status = 0;
758bail:
759 if (new_bh)
760 brelse(new_bh);
761
762 mlog_exit(status);
763 return status;
764}
765
350/* returns a bh of the 1st new block in the allocation. */ 766/* returns a bh of the 1st new block in the allocation. */
351int ocfs2_do_extend_dir(struct super_block *sb, 767static int ocfs2_do_extend_dir(struct super_block *sb,
352 handle_t *handle, 768 handle_t *handle,
353 struct inode *dir, 769 struct inode *dir,
354 struct buffer_head *parent_fe_bh, 770 struct buffer_head *parent_fe_bh,
355 struct ocfs2_alloc_context *data_ac, 771 struct ocfs2_alloc_context *data_ac,
356 struct ocfs2_alloc_context *meta_ac, 772 struct ocfs2_alloc_context *meta_ac,
357 struct buffer_head **new_bh) 773 struct buffer_head **new_bh)
358{ 774{
359 int status; 775 int status;
360 int extend; 776 int extend;