aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMark Fasheh <mark.fasheh@oracle.com>2007-09-12 16:01:18 -0400
committerMark Fasheh <mark.fasheh@oracle.com>2007-10-12 14:54:40 -0400
commit23193e513d1cd69411469f028d56fd175d4a6b07 (patch)
tree18c2c6019d4ba6253a7c2ce87b53a118801ce534 /fs
parent1afc32b952335f665327a1a9001ba1b44bb76fd9 (diff)
ocfs2: Read support for directories with inline data
This splits out extent based directory read support and implements inline-data versions of those functions. All knowledge of inline-data versus extent based directories is internalized. For lookups the code uses ocfs2_find_entry_id(), full dir iterations make use of ocfs2_dir_foreach_blk_id(). Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com> Reviewed-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/dir.c176
1 files changed, 168 insertions, 8 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index f2e2ffbf6c95..8deed89330c7 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -81,6 +81,10 @@ static int ocfs2_do_extend_dir(struct super_block *sb,
81 struct ocfs2_alloc_context *meta_ac, 81 struct ocfs2_alloc_context *meta_ac,
82 struct buffer_head **new_bh); 82 struct buffer_head **new_bh);
83 83
84/*
85 * bh passed here can be an inode block or a dir data block, depending
86 * on the inode inline data flag.
87 */
84static int ocfs2_check_dir_entry(struct inode * dir, 88static int ocfs2_check_dir_entry(struct inode * dir,
85 struct ocfs2_dir_entry * de, 89 struct ocfs2_dir_entry * de,
86 struct buffer_head * bh, 90 struct buffer_head * bh,
@@ -125,6 +129,8 @@ static int inline ocfs2_search_dirblock(struct buffer_head *bh,
125 struct inode *dir, 129 struct inode *dir,
126 const char *name, int namelen, 130 const char *name, int namelen,
127 unsigned long offset, 131 unsigned long offset,
132 char *first_de,
133 unsigned int bytes,
128 struct ocfs2_dir_entry **res_dir) 134 struct ocfs2_dir_entry **res_dir)
129{ 135{
130 struct ocfs2_dir_entry *de; 136 struct ocfs2_dir_entry *de;
@@ -134,8 +140,8 @@ static int inline ocfs2_search_dirblock(struct buffer_head *bh,
134 140
135 mlog_entry_void(); 141 mlog_entry_void();
136 142
137 de_buf = bh->b_data; 143 de_buf = first_de;
138 dlimit = de_buf + dir->i_sb->s_blocksize; 144 dlimit = de_buf + bytes;
139 145
140 while (de_buf < dlimit) { 146 while (de_buf < dlimit) {
141 /* this code is executed quadratically often */ 147 /* this code is executed quadratically often */
@@ -171,9 +177,39 @@ bail:
171 return ret; 177 return ret;
172} 178}
173 179
174struct buffer_head *ocfs2_find_entry(const char *name, int namelen, 180static struct buffer_head *ocfs2_find_entry_id(const char *name,
175 struct inode *dir, 181 int namelen,
176 struct ocfs2_dir_entry **res_dir) 182 struct inode *dir,
183 struct ocfs2_dir_entry **res_dir)
184{
185 int ret, found;
186 struct buffer_head *di_bh = NULL;
187 struct ocfs2_dinode *di;
188 struct ocfs2_inline_data *data;
189
190 ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
191 &di_bh, OCFS2_BH_CACHED, dir);
192 if (ret) {
193 mlog_errno(ret);
194 goto out;
195 }
196
197 di = (struct ocfs2_dinode *)di_bh->b_data;
198 data = &di->id2.i_data;
199
200 found = ocfs2_search_dirblock(di_bh, dir, name, namelen, 0,
201 data->id_data, i_size_read(dir), res_dir);
202 if (found == 1)
203 return di_bh;
204
205 brelse(di_bh);
206out:
207 return NULL;
208}
209
210struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen,
211 struct inode *dir,
212 struct ocfs2_dir_entry **res_dir)
177{ 213{
178 struct super_block *sb; 214 struct super_block *sb;
179 struct buffer_head *bh_use[NAMEI_RA_SIZE]; 215 struct buffer_head *bh_use[NAMEI_RA_SIZE];
@@ -188,7 +224,6 @@ struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
188 224
189 mlog_entry_void(); 225 mlog_entry_void();
190 226
191 *res_dir = NULL;
192 sb = dir->i_sb; 227 sb = dir->i_sb;
193 228
194 nblocks = i_size_read(dir) >> sb->s_blocksize_bits; 229 nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
@@ -236,6 +271,7 @@ restart:
236 } 271 }
237 i = ocfs2_search_dirblock(bh, dir, name, namelen, 272 i = ocfs2_search_dirblock(bh, dir, name, namelen,
238 block << sb->s_blocksize_bits, 273 block << sb->s_blocksize_bits,
274 bh->b_data, sb->s_blocksize,
239 res_dir); 275 res_dir);
240 if (i == 1) { 276 if (i == 1) {
241 OCFS2_I(dir)->ip_dir_start_lookup = block; 277 OCFS2_I(dir)->ip_dir_start_lookup = block;
@@ -271,6 +307,30 @@ cleanup_and_exit:
271 return ret; 307 return ret;
272} 308}
273 309
310/*
311 * Try to find an entry of the provided name within 'dir'.
312 *
313 * If nothing was found, NULL is returned. Otherwise, a buffer_head
314 * and pointer to the dir entry are passed back.
315 *
316 * Caller can NOT assume anything about the contents of the
317 * buffer_head - it is passed back only so that it can be passed into
318 * any one of the manipulation functions (add entry, delete entry,
319 * etc). As an example, bh in the extent directory case is a data
320 * block, in the inline-data case it actually points to an inode.
321 */
322struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
323 struct inode *dir,
324 struct ocfs2_dir_entry **res_dir)
325{
326 *res_dir = NULL;
327
328 if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
329 return ocfs2_find_entry_id(name, namelen, dir, res_dir);
330
331 return ocfs2_find_entry_el(name, namelen, dir, res_dir);
332}
333
274int ocfs2_update_entry(struct inode *dir, handle_t *handle, 334int ocfs2_update_entry(struct inode *dir, handle_t *handle,
275 struct buffer_head *de_bh, struct ocfs2_dir_entry *de, 335 struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
276 struct inode *new_entry_inode) 336 struct inode *new_entry_inode)
@@ -459,8 +519,98 @@ bail:
459 return retval; 519 return retval;
460} 520}
461 521
462static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, 522static int ocfs2_dir_foreach_blk_id(struct inode *inode,
463 loff_t *f_pos, void *priv, filldir_t filldir) 523 unsigned long *f_version,
524 loff_t *f_pos, void *priv,
525 filldir_t filldir)
526{
527 int ret, i, filldir_ret;
528 unsigned long offset = *f_pos;
529 struct buffer_head *di_bh = NULL;
530 struct ocfs2_dinode *di;
531 struct ocfs2_inline_data *data;
532 struct ocfs2_dir_entry *de;
533
534 ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
535 &di_bh, OCFS2_BH_CACHED, inode);
536 if (ret) {
537 mlog(ML_ERROR, "Unable to read inode block for dir %llu\n",
538 (unsigned long long)OCFS2_I(inode)->ip_blkno);
539 goto out;
540 }
541
542 di = (struct ocfs2_dinode *)di_bh->b_data;
543 data = &di->id2.i_data;
544
545 while (*f_pos < i_size_read(inode)) {
546revalidate:
547 /* If the dir block has changed since the last call to
548 * readdir(2), then we might be pointing to an invalid
549 * dirent right now. Scan from the start of the block
550 * to make sure. */
551 if (*f_version != inode->i_version) {
552 for (i = 0; i < i_size_read(inode) && i < offset; ) {
553 de = (struct ocfs2_dir_entry *)
554 (data->id_data + i);
555 /* It's too expensive to do a full
556 * dirent test each time round this
557 * loop, but we do have to test at
558 * least that it is non-zero. A
559 * failure will be detected in the
560 * dirent test below. */
561 if (le16_to_cpu(de->rec_len) <
562 OCFS2_DIR_REC_LEN(1))
563 break;
564 i += le16_to_cpu(de->rec_len);
565 }
566 *f_pos = offset = i;
567 *f_version = inode->i_version;
568 }
569
570 de = (struct ocfs2_dir_entry *) (data->id_data + *f_pos);
571 if (!ocfs2_check_dir_entry(inode, de, di_bh, *f_pos)) {
572 /* On error, skip the f_pos to the end. */
573 *f_pos = i_size_read(inode);
574 goto out;
575 }
576 offset += le16_to_cpu(de->rec_len);
577 if (le64_to_cpu(de->inode)) {
578 /* We might block in the next section
579 * if the data destination is
580 * currently swapped out. So, use a
581 * version stamp to detect whether or
582 * not the directory has been modified
583 * during the copy operation.
584 */
585 unsigned long version = *f_version;
586 unsigned char d_type = DT_UNKNOWN;
587
588 if (de->file_type < OCFS2_FT_MAX)
589 d_type = ocfs2_filetype_table[de->file_type];
590
591 filldir_ret = filldir(priv, de->name,
592 de->name_len,
593 *f_pos,
594 le64_to_cpu(de->inode),
595 d_type);
596 if (filldir_ret)
597 break;
598 if (version != *f_version)
599 goto revalidate;
600 }
601 *f_pos += le16_to_cpu(de->rec_len);
602 }
603
604out:
605 brelse(di_bh);
606
607 return 0;
608}
609
610static int ocfs2_dir_foreach_blk_el(struct inode *inode,
611 unsigned long *f_version,
612 loff_t *f_pos, void *priv,
613 filldir_t filldir)
464{ 614{
465 int error = 0; 615 int error = 0;
466 unsigned long offset, blk, last_ra_blk = 0; 616 unsigned long offset, blk, last_ra_blk = 0;
@@ -576,6 +726,16 @@ out:
576 return stored; 726 return stored;
577} 727}
578 728
729static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version,
730 loff_t *f_pos, void *priv, filldir_t filldir)
731{
732 if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
733 return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv,
734 filldir);
735
736 return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir);
737}
738
579/* 739/*
580 * This is intended to be called from inside other kernel functions, 740 * This is intended to be called from inside other kernel functions,
581 * so we fake some arguments. 741 * so we fake some arguments.