aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-05-15 21:02:48 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-06-29 04:46:49 -0400
commit5ded75ec4c576577cae7d556e671d11d0c80c2fc (patch)
tree964c5d165f74933df96d6fa16f9bd866a7308727
parent5f99f4e79abc64ed9d93a4b0158b21c64ff7f478 (diff)
[readdir] convert ext3
new helper: dir_relax(inode). Call when you are in location that will _not_ be invalidated by directory modifications (block boundary, in case of ext*). Returns whether the directory has survived (dropping i_mutex allows rmdir to kill the sucker; if it returns false to us, ->iterate() is obviously done) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/ext3/dir.c157
-rw-r--r--include/linux/fs.h6
2 files changed, 70 insertions, 93 deletions
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 87eccbbca255..f522425aaa24 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -28,8 +28,7 @@ static unsigned char ext3_filetype_table[] = {
28 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK 28 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
29}; 29};
30 30
31static int ext3_dx_readdir(struct file * filp, 31static int ext3_dx_readdir(struct file *, struct dir_context *);
32 void * dirent, filldir_t filldir);
33 32
34static unsigned char get_dtype(struct super_block *sb, int filetype) 33static unsigned char get_dtype(struct super_block *sb, int filetype)
35{ 34{
@@ -91,36 +90,30 @@ int ext3_check_dir_entry (const char * function, struct inode * dir,
91 return error_msg == NULL ? 1 : 0; 90 return error_msg == NULL ? 1 : 0;
92} 91}
93 92
94static int ext3_readdir(struct file * filp, 93static int ext3_readdir(struct file *file, struct dir_context *ctx)
95 void * dirent, filldir_t filldir)
96{ 94{
97 int error = 0;
98 unsigned long offset; 95 unsigned long offset;
99 int i, stored; 96 int i;
100 struct ext3_dir_entry_2 *de; 97 struct ext3_dir_entry_2 *de;
101 int err; 98 int err;
102 struct inode *inode = file_inode(filp); 99 struct inode *inode = file_inode(file);
103 struct super_block *sb = inode->i_sb; 100 struct super_block *sb = inode->i_sb;
104 int ret = 0;
105 int dir_has_error = 0; 101 int dir_has_error = 0;
106 102
107 if (is_dx_dir(inode)) { 103 if (is_dx_dir(inode)) {
108 err = ext3_dx_readdir(filp, dirent, filldir); 104 err = ext3_dx_readdir(file, ctx);
109 if (err != ERR_BAD_DX_DIR) { 105 if (err != ERR_BAD_DX_DIR)
110 ret = err; 106 return err;
111 goto out;
112 }
113 /* 107 /*
114 * We don't set the inode dirty flag since it's not 108 * We don't set the inode dirty flag since it's not
115 * critical that it get flushed back to the disk. 109 * critical that it get flushed back to the disk.
116 */ 110 */
117 EXT3_I(file_inode(filp))->i_flags &= ~EXT3_INDEX_FL; 111 EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL;
118 } 112 }
119 stored = 0; 113 offset = ctx->pos & (sb->s_blocksize - 1);
120 offset = filp->f_pos & (sb->s_blocksize - 1);
121 114
122 while (!error && !stored && filp->f_pos < inode->i_size) { 115 while (ctx->pos < inode->i_size) {
123 unsigned long blk = filp->f_pos >> EXT3_BLOCK_SIZE_BITS(sb); 116 unsigned long blk = ctx->pos >> EXT3_BLOCK_SIZE_BITS(sb);
124 struct buffer_head map_bh; 117 struct buffer_head map_bh;
125 struct buffer_head *bh = NULL; 118 struct buffer_head *bh = NULL;
126 119
@@ -129,12 +122,12 @@ static int ext3_readdir(struct file * filp,
129 if (err > 0) { 122 if (err > 0) {
130 pgoff_t index = map_bh.b_blocknr >> 123 pgoff_t index = map_bh.b_blocknr >>
131 (PAGE_CACHE_SHIFT - inode->i_blkbits); 124 (PAGE_CACHE_SHIFT - inode->i_blkbits);
132 if (!ra_has_index(&filp->f_ra, index)) 125 if (!ra_has_index(&file->f_ra, index))
133 page_cache_sync_readahead( 126 page_cache_sync_readahead(
134 sb->s_bdev->bd_inode->i_mapping, 127 sb->s_bdev->bd_inode->i_mapping,
135 &filp->f_ra, filp, 128 &file->f_ra, file,
136 index, 1); 129 index, 1);
137 filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; 130 file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
138 bh = ext3_bread(NULL, inode, blk, 0, &err); 131 bh = ext3_bread(NULL, inode, blk, 0, &err);
139 } 132 }
140 133
@@ -146,22 +139,21 @@ static int ext3_readdir(struct file * filp,
146 if (!dir_has_error) { 139 if (!dir_has_error) {
147 ext3_error(sb, __func__, "directory #%lu " 140 ext3_error(sb, __func__, "directory #%lu "
148 "contains a hole at offset %lld", 141 "contains a hole at offset %lld",
149 inode->i_ino, filp->f_pos); 142 inode->i_ino, ctx->pos);
150 dir_has_error = 1; 143 dir_has_error = 1;
151 } 144 }
152 /* corrupt size? Maybe no more blocks to read */ 145 /* corrupt size? Maybe no more blocks to read */
153 if (filp->f_pos > inode->i_blocks << 9) 146 if (ctx->pos > inode->i_blocks << 9)
154 break; 147 break;
155 filp->f_pos += sb->s_blocksize - offset; 148 ctx->pos += sb->s_blocksize - offset;
156 continue; 149 continue;
157 } 150 }
158 151
159revalidate:
160 /* If the dir block has changed since the last call to 152 /* If the dir block has changed since the last call to
161 * readdir(2), then we might be pointing to an invalid 153 * readdir(2), then we might be pointing to an invalid
162 * dirent right now. Scan from the start of the block 154 * dirent right now. Scan from the start of the block
163 * to make sure. */ 155 * to make sure. */
164 if (filp->f_version != inode->i_version) { 156 if (offset && file->f_version != inode->i_version) {
165 for (i = 0; i < sb->s_blocksize && i < offset; ) { 157 for (i = 0; i < sb->s_blocksize && i < offset; ) {
166 de = (struct ext3_dir_entry_2 *) 158 de = (struct ext3_dir_entry_2 *)
167 (bh->b_data + i); 159 (bh->b_data + i);
@@ -177,53 +169,40 @@ revalidate:
177 i += ext3_rec_len_from_disk(de->rec_len); 169 i += ext3_rec_len_from_disk(de->rec_len);
178 } 170 }
179 offset = i; 171 offset = i;
180 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) 172 ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
181 | offset; 173 | offset;
182 filp->f_version = inode->i_version; 174 file->f_version = inode->i_version;
183 } 175 }
184 176
185 while (!error && filp->f_pos < inode->i_size 177 while (ctx->pos < inode->i_size
186 && offset < sb->s_blocksize) { 178 && offset < sb->s_blocksize) {
187 de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); 179 de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
188 if (!ext3_check_dir_entry ("ext3_readdir", inode, de, 180 if (!ext3_check_dir_entry ("ext3_readdir", inode, de,
189 bh, offset)) { 181 bh, offset)) {
190 /* On error, skip the f_pos to the 182 /* On error, skip the to the
191 next block. */ 183 next block. */
192 filp->f_pos = (filp->f_pos | 184 ctx->pos = (ctx->pos |
193 (sb->s_blocksize - 1)) + 1; 185 (sb->s_blocksize - 1)) + 1;
194 brelse (bh); 186 break;
195 ret = stored;
196 goto out;
197 } 187 }
198 offset += ext3_rec_len_from_disk(de->rec_len); 188 offset += ext3_rec_len_from_disk(de->rec_len);
199 if (le32_to_cpu(de->inode)) { 189 if (le32_to_cpu(de->inode)) {
200 /* We might block in the next section 190 if (!dir_emit(ctx, de->name, de->name_len,
201 * if the data destination is 191 le32_to_cpu(de->inode),
202 * currently swapped out. So, use a 192 get_dtype(sb, de->file_type))) {
203 * version stamp to detect whether or 193 brelse(bh);
204 * not the directory has been modified 194 return 0;
205 * during the copy operation. 195 }
206 */
207 u64 version = filp->f_version;
208
209 error = filldir(dirent, de->name,
210 de->name_len,
211 filp->f_pos,
212 le32_to_cpu(de->inode),
213 get_dtype(sb, de->file_type));
214 if (error)
215 break;
216 if (version != filp->f_version)
217 goto revalidate;
218 stored ++;
219 } 196 }
220 filp->f_pos += ext3_rec_len_from_disk(de->rec_len); 197 ctx->pos += ext3_rec_len_from_disk(de->rec_len);
221 } 198 }
222 offset = 0; 199 offset = 0;
223 brelse (bh); 200 brelse (bh);
201 if (ctx->pos < inode->i_size)
202 if (!dir_relax(inode))
203 return 0;
224 } 204 }
225out: 205 return 0;
226 return ret;
227} 206}
228 207
229static inline int is_32bit_api(void) 208static inline int is_32bit_api(void)
@@ -452,62 +431,54 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
452 * for all entres on the fname linked list. (Normally there is only 431 * for all entres on the fname linked list. (Normally there is only
453 * one entry on the linked list, unless there are 62 bit hash collisions.) 432 * one entry on the linked list, unless there are 62 bit hash collisions.)
454 */ 433 */
455static int call_filldir(struct file * filp, void * dirent, 434static bool call_filldir(struct file *file, struct dir_context *ctx,
456 filldir_t filldir, struct fname *fname) 435 struct fname *fname)
457{ 436{
458 struct dir_private_info *info = filp->private_data; 437 struct dir_private_info *info = file->private_data;
459 loff_t curr_pos; 438 struct inode *inode = file_inode(file);
460 struct inode *inode = file_inode(filp); 439 struct super_block *sb = inode->i_sb;
461 struct super_block * sb;
462 int error;
463
464 sb = inode->i_sb;
465 440
466 if (!fname) { 441 if (!fname) {
467 printk("call_filldir: called with null fname?!?\n"); 442 printk("call_filldir: called with null fname?!?\n");
468 return 0; 443 return true;
469 } 444 }
470 curr_pos = hash2pos(filp, fname->hash, fname->minor_hash); 445 ctx->pos = hash2pos(file, fname->hash, fname->minor_hash);
471 while (fname) { 446 while (fname) {
472 error = filldir(dirent, fname->name, 447 if (!dir_emit(ctx, fname->name, fname->name_len,
473 fname->name_len, curr_pos,
474 fname->inode, 448 fname->inode,
475 get_dtype(sb, fname->file_type)); 449 get_dtype(sb, fname->file_type))) {
476 if (error) {
477 filp->f_pos = curr_pos;
478 info->extra_fname = fname; 450 info->extra_fname = fname;
479 return error; 451 return false;
480 } 452 }
481 fname = fname->next; 453 fname = fname->next;
482 } 454 }
483 return 0; 455 return true;
484} 456}
485 457
486static int ext3_dx_readdir(struct file * filp, 458static int ext3_dx_readdir(struct file *file, struct dir_context *ctx)
487 void * dirent, filldir_t filldir)
488{ 459{
489 struct dir_private_info *info = filp->private_data; 460 struct dir_private_info *info = file->private_data;
490 struct inode *inode = file_inode(filp); 461 struct inode *inode = file_inode(file);
491 struct fname *fname; 462 struct fname *fname;
492 int ret; 463 int ret;
493 464
494 if (!info) { 465 if (!info) {
495 info = ext3_htree_create_dir_info(filp, filp->f_pos); 466 info = ext3_htree_create_dir_info(file, ctx->pos);
496 if (!info) 467 if (!info)
497 return -ENOMEM; 468 return -ENOMEM;
498 filp->private_data = info; 469 file->private_data = info;
499 } 470 }
500 471
501 if (filp->f_pos == ext3_get_htree_eof(filp)) 472 if (ctx->pos == ext3_get_htree_eof(file))
502 return 0; /* EOF */ 473 return 0; /* EOF */
503 474
504 /* Some one has messed with f_pos; reset the world */ 475 /* Some one has messed with f_pos; reset the world */
505 if (info->last_pos != filp->f_pos) { 476 if (info->last_pos != ctx->pos) {
506 free_rb_tree_fname(&info->root); 477 free_rb_tree_fname(&info->root);
507 info->curr_node = NULL; 478 info->curr_node = NULL;
508 info->extra_fname = NULL; 479 info->extra_fname = NULL;
509 info->curr_hash = pos2maj_hash(filp, filp->f_pos); 480 info->curr_hash = pos2maj_hash(file, ctx->pos);
510 info->curr_minor_hash = pos2min_hash(filp, filp->f_pos); 481 info->curr_minor_hash = pos2min_hash(file, ctx->pos);
511 } 482 }
512 483
513 /* 484 /*
@@ -515,7 +486,7 @@ static int ext3_dx_readdir(struct file * filp,
515 * chain, return them first. 486 * chain, return them first.
516 */ 487 */
517 if (info->extra_fname) { 488 if (info->extra_fname) {
518 if (call_filldir(filp, dirent, filldir, info->extra_fname)) 489 if (!call_filldir(file, ctx, info->extra_fname))
519 goto finished; 490 goto finished;
520 info->extra_fname = NULL; 491 info->extra_fname = NULL;
521 goto next_node; 492 goto next_node;
@@ -529,17 +500,17 @@ static int ext3_dx_readdir(struct file * filp,
529 * cached entries. 500 * cached entries.
530 */ 501 */
531 if ((!info->curr_node) || 502 if ((!info->curr_node) ||
532 (filp->f_version != inode->i_version)) { 503 (file->f_version != inode->i_version)) {
533 info->curr_node = NULL; 504 info->curr_node = NULL;
534 free_rb_tree_fname(&info->root); 505 free_rb_tree_fname(&info->root);
535 filp->f_version = inode->i_version; 506 file->f_version = inode->i_version;
536 ret = ext3_htree_fill_tree(filp, info->curr_hash, 507 ret = ext3_htree_fill_tree(file, info->curr_hash,
537 info->curr_minor_hash, 508 info->curr_minor_hash,
538 &info->next_hash); 509 &info->next_hash);
539 if (ret < 0) 510 if (ret < 0)
540 return ret; 511 return ret;
541 if (ret == 0) { 512 if (ret == 0) {
542 filp->f_pos = ext3_get_htree_eof(filp); 513 ctx->pos = ext3_get_htree_eof(file);
543 break; 514 break;
544 } 515 }
545 info->curr_node = rb_first(&info->root); 516 info->curr_node = rb_first(&info->root);
@@ -548,7 +519,7 @@ static int ext3_dx_readdir(struct file * filp,
548 fname = rb_entry(info->curr_node, struct fname, rb_hash); 519 fname = rb_entry(info->curr_node, struct fname, rb_hash);
549 info->curr_hash = fname->hash; 520 info->curr_hash = fname->hash;
550 info->curr_minor_hash = fname->minor_hash; 521 info->curr_minor_hash = fname->minor_hash;
551 if (call_filldir(filp, dirent, filldir, fname)) 522 if (!call_filldir(file, ctx, fname))
552 break; 523 break;
553 next_node: 524 next_node:
554 info->curr_node = rb_next(info->curr_node); 525 info->curr_node = rb_next(info->curr_node);
@@ -559,7 +530,7 @@ static int ext3_dx_readdir(struct file * filp,
559 info->curr_minor_hash = fname->minor_hash; 530 info->curr_minor_hash = fname->minor_hash;
560 } else { 531 } else {
561 if (info->next_hash == ~0) { 532 if (info->next_hash == ~0) {
562 filp->f_pos = ext3_get_htree_eof(filp); 533 ctx->pos = ext3_get_htree_eof(file);
563 break; 534 break;
564 } 535 }
565 info->curr_hash = info->next_hash; 536 info->curr_hash = info->next_hash;
@@ -567,7 +538,7 @@ static int ext3_dx_readdir(struct file * filp,
567 } 538 }
568 } 539 }
569finished: 540finished:
570 info->last_pos = filp->f_pos; 541 info->last_pos = ctx->pos;
571 return 0; 542 return 0;
572} 543}
573 544
@@ -582,7 +553,7 @@ static int ext3_release_dir (struct inode * inode, struct file * filp)
582const struct file_operations ext3_dir_operations = { 553const struct file_operations ext3_dir_operations = {
583 .llseek = ext3_dir_llseek, 554 .llseek = ext3_dir_llseek,
584 .read = generic_read_dir, 555 .read = generic_read_dir,
585 .readdir = ext3_readdir, 556 .iterate = ext3_readdir,
586 .unlocked_ioctl = ext3_ioctl, 557 .unlocked_ioctl = ext3_ioctl,
587#ifdef CONFIG_COMPAT 558#ifdef CONFIG_COMPAT
588 .compat_ioctl = ext3_compat_ioctl, 559 .compat_ioctl = ext3_compat_ioctl,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 40293a6ce804..aa9770c7e8df 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2725,5 +2725,11 @@ static inline bool dir_emit_dots(struct file *file, struct dir_context *ctx)
2725 } 2725 }
2726 return true; 2726 return true;
2727} 2727}
2728static inline bool dir_relax(struct inode *inode)
2729{
2730 mutex_unlock(&inode->i_mutex);
2731 mutex_lock(&inode->i_mutex);
2732 return !IS_DEADDIR(inode);
2733}
2728 2734
2729#endif /* _LINUX_FS_H */ 2735#endif /* _LINUX_FS_H */