aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/dir.c158
-rw-r--r--fs/ext4/ext4.h2
-rw-r--r--fs/ext4/inline.c164
3 files changed, 134 insertions, 190 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index f8d56e4254e0..3c7d288ae94c 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -29,8 +29,7 @@
29#include "ext4.h" 29#include "ext4.h"
30#include "xattr.h" 30#include "xattr.h"
31 31
32static int ext4_dx_readdir(struct file *filp, 32static int ext4_dx_readdir(struct file *, struct dir_context *);
33 void *dirent, filldir_t filldir);
34 33
35/** 34/**
36 * Check if the given dir-inode refers to an htree-indexed directory 35 * Check if the given dir-inode refers to an htree-indexed directory
@@ -103,60 +102,56 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
103 return 1; 102 return 1;
104} 103}
105 104
106static int ext4_readdir(struct file *filp, 105static int ext4_readdir(struct file *file, struct dir_context *ctx)
107 void *dirent, filldir_t filldir)
108{ 106{
109 int error = 0;
110 unsigned int offset; 107 unsigned int offset;
111 int i, stored; 108 int i, stored;
112 struct ext4_dir_entry_2 *de; 109 struct ext4_dir_entry_2 *de;
113 int err; 110 int err;
114 struct inode *inode = file_inode(filp); 111 struct inode *inode = file_inode(file);
115 struct super_block *sb = inode->i_sb; 112 struct super_block *sb = inode->i_sb;
116 int ret = 0;
117 int dir_has_error = 0; 113 int dir_has_error = 0;
118 114
119 if (is_dx_dir(inode)) { 115 if (is_dx_dir(inode)) {
120 err = ext4_dx_readdir(filp, dirent, filldir); 116 err = ext4_dx_readdir(file, ctx);
121 if (err != ERR_BAD_DX_DIR) { 117 if (err != ERR_BAD_DX_DIR) {
122 ret = err; 118 return err;
123 goto out;
124 } 119 }
125 /* 120 /*
126 * We don't set the inode dirty flag since it's not 121 * We don't set the inode dirty flag since it's not
127 * critical that it get flushed back to the disk. 122 * critical that it get flushed back to the disk.
128 */ 123 */
129 ext4_clear_inode_flag(file_inode(filp), 124 ext4_clear_inode_flag(file_inode(file),
130 EXT4_INODE_INDEX); 125 EXT4_INODE_INDEX);
131 } 126 }
132 127
133 if (ext4_has_inline_data(inode)) { 128 if (ext4_has_inline_data(inode)) {
134 int has_inline_data = 1; 129 int has_inline_data = 1;
135 ret = ext4_read_inline_dir(filp, dirent, filldir, 130 int ret = ext4_read_inline_dir(file, ctx,
136 &has_inline_data); 131 &has_inline_data);
137 if (has_inline_data) 132 if (has_inline_data)
138 return ret; 133 return ret;
139 } 134 }
140 135
141 stored = 0; 136 stored = 0;
142 offset = filp->f_pos & (sb->s_blocksize - 1); 137 offset = ctx->pos & (sb->s_blocksize - 1);
143 138
144 while (!error && !stored && filp->f_pos < inode->i_size) { 139 while (ctx->pos < inode->i_size) {
145 struct ext4_map_blocks map; 140 struct ext4_map_blocks map;
146 struct buffer_head *bh = NULL; 141 struct buffer_head *bh = NULL;
147 142
148 map.m_lblk = filp->f_pos >> EXT4_BLOCK_SIZE_BITS(sb); 143 map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
149 map.m_len = 1; 144 map.m_len = 1;
150 err = ext4_map_blocks(NULL, inode, &map, 0); 145 err = ext4_map_blocks(NULL, inode, &map, 0);
151 if (err > 0) { 146 if (err > 0) {
152 pgoff_t index = map.m_pblk >> 147 pgoff_t index = map.m_pblk >>
153 (PAGE_CACHE_SHIFT - inode->i_blkbits); 148 (PAGE_CACHE_SHIFT - inode->i_blkbits);
154 if (!ra_has_index(&filp->f_ra, index)) 149 if (!ra_has_index(&file->f_ra, index))
155 page_cache_sync_readahead( 150 page_cache_sync_readahead(
156 sb->s_bdev->bd_inode->i_mapping, 151 sb->s_bdev->bd_inode->i_mapping,
157 &filp->f_ra, filp, 152 &file->f_ra, file,
158 index, 1); 153 index, 1);
159 filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; 154 file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
160 bh = ext4_bread(NULL, inode, map.m_lblk, 0, &err); 155 bh = ext4_bread(NULL, inode, map.m_lblk, 0, &err);
161 } 156 }
162 157
@@ -166,16 +161,16 @@ static int ext4_readdir(struct file *filp,
166 */ 161 */
167 if (!bh) { 162 if (!bh) {
168 if (!dir_has_error) { 163 if (!dir_has_error) {
169 EXT4_ERROR_FILE(filp, 0, 164 EXT4_ERROR_FILE(file, 0,
170 "directory contains a " 165 "directory contains a "
171 "hole at offset %llu", 166 "hole at offset %llu",
172 (unsigned long long) filp->f_pos); 167 (unsigned long long) ctx->pos);
173 dir_has_error = 1; 168 dir_has_error = 1;
174 } 169 }
175 /* corrupt size? Maybe no more blocks to read */ 170 /* corrupt size? Maybe no more blocks to read */
176 if (filp->f_pos > inode->i_blocks << 9) 171 if (ctx->pos > inode->i_blocks << 9)
177 break; 172 break;
178 filp->f_pos += sb->s_blocksize - offset; 173 ctx->pos += sb->s_blocksize - offset;
179 continue; 174 continue;
180 } 175 }
181 176
@@ -183,21 +178,20 @@ static int ext4_readdir(struct file *filp,
183 if (!buffer_verified(bh) && 178 if (!buffer_verified(bh) &&
184 !ext4_dirent_csum_verify(inode, 179 !ext4_dirent_csum_verify(inode,
185 (struct ext4_dir_entry *)bh->b_data)) { 180 (struct ext4_dir_entry *)bh->b_data)) {
186 EXT4_ERROR_FILE(filp, 0, "directory fails checksum " 181 EXT4_ERROR_FILE(file, 0, "directory fails checksum "
187 "at offset %llu", 182 "at offset %llu",
188 (unsigned long long)filp->f_pos); 183 (unsigned long long)ctx->pos);
189 filp->f_pos += sb->s_blocksize - offset; 184 ctx->pos += sb->s_blocksize - offset;
190 brelse(bh); 185 brelse(bh);
191 continue; 186 continue;
192 } 187 }
193 set_buffer_verified(bh); 188 set_buffer_verified(bh);
194 189
195revalidate:
196 /* If the dir block has changed since the last call to 190 /* If the dir block has changed since the last call to
197 * readdir(2), then we might be pointing to an invalid 191 * readdir(2), then we might be pointing to an invalid
198 * dirent right now. Scan from the start of the block 192 * dirent right now. Scan from the start of the block
199 * to make sure. */ 193 * to make sure. */
200 if (filp->f_version != inode->i_version) { 194 if (file->f_version != inode->i_version) {
201 for (i = 0; i < sb->s_blocksize && i < offset; ) { 195 for (i = 0; i < sb->s_blocksize && i < offset; ) {
202 de = (struct ext4_dir_entry_2 *) 196 de = (struct ext4_dir_entry_2 *)
203 (bh->b_data + i); 197 (bh->b_data + i);
@@ -214,57 +208,46 @@ revalidate:
214 sb->s_blocksize); 208 sb->s_blocksize);
215 } 209 }
216 offset = i; 210 offset = i;
217 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) 211 ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
218 | offset; 212 | offset;
219 filp->f_version = inode->i_version; 213 file->f_version = inode->i_version;
220 } 214 }
221 215
222 while (!error && filp->f_pos < inode->i_size 216 while (ctx->pos < inode->i_size
223 && offset < sb->s_blocksize) { 217 && offset < sb->s_blocksize) {
224 de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); 218 de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
225 if (ext4_check_dir_entry(inode, filp, de, bh, 219 if (ext4_check_dir_entry(inode, file, de, bh,
226 bh->b_data, bh->b_size, 220 bh->b_data, bh->b_size,
227 offset)) { 221 offset)) {
228 /* 222 /*
229 * On error, skip the f_pos to the next block 223 * On error, skip to the next block
230 */ 224 */
231 filp->f_pos = (filp->f_pos | 225 ctx->pos = (ctx->pos |
232 (sb->s_blocksize - 1)) + 1; 226 (sb->s_blocksize - 1)) + 1;
233 brelse(bh); 227 break;
234 ret = stored;
235 goto out;
236 } 228 }
237 offset += ext4_rec_len_from_disk(de->rec_len, 229 offset += ext4_rec_len_from_disk(de->rec_len,
238 sb->s_blocksize); 230 sb->s_blocksize);
239 if (le32_to_cpu(de->inode)) { 231 if (le32_to_cpu(de->inode)) {
240 /* We might block in the next section 232 if (!dir_emit(ctx, de->name,
241 * if the data destination is
242 * currently swapped out. So, use a
243 * version stamp to detect whether or
244 * not the directory has been modified
245 * during the copy operation.
246 */
247 u64 version = filp->f_version;
248
249 error = filldir(dirent, de->name,
250 de->name_len, 233 de->name_len,
251 filp->f_pos,
252 le32_to_cpu(de->inode), 234 le32_to_cpu(de->inode),
253 get_dtype(sb, de->file_type)); 235 get_dtype(sb, de->file_type))) {
254 if (error) 236 brelse(bh);
255 break; 237 return 0;
256 if (version != filp->f_version) 238 }
257 goto revalidate;
258 stored++;
259 } 239 }
260 filp->f_pos += ext4_rec_len_from_disk(de->rec_len, 240 ctx->pos += ext4_rec_len_from_disk(de->rec_len,
261 sb->s_blocksize); 241 sb->s_blocksize);
262 } 242 }
263 offset = 0; 243 offset = 0;
264 brelse(bh); 244 brelse(bh);
245 if (ctx->pos < inode->i_size) {
246 if (!dir_relax(inode))
247 return 0;
248 }
265 } 249 }
266out: 250 return 0;
267 return ret;
268} 251}
269 252
270static inline int is_32bit_api(void) 253static inline int is_32bit_api(void)
@@ -492,16 +475,12 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
492 * for all entres on the fname linked list. (Normally there is only 475 * for all entres on the fname linked list. (Normally there is only
493 * one entry on the linked list, unless there are 62 bit hash collisions.) 476 * one entry on the linked list, unless there are 62 bit hash collisions.)
494 */ 477 */
495static int call_filldir(struct file *filp, void *dirent, 478static int call_filldir(struct file *file, struct dir_context *ctx,
496 filldir_t filldir, struct fname *fname) 479 struct fname *fname)
497{ 480{
498 struct dir_private_info *info = filp->private_data; 481 struct dir_private_info *info = file->private_data;
499 loff_t curr_pos; 482 struct inode *inode = file_inode(file);
500 struct inode *inode = file_inode(filp); 483 struct super_block *sb = inode->i_sb;
501 struct super_block *sb;
502 int error;
503
504 sb = inode->i_sb;
505 484
506 if (!fname) { 485 if (!fname) {
507 ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: " 486 ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: "
@@ -509,47 +488,44 @@ static int call_filldir(struct file *filp, void *dirent,
509 inode->i_ino, current->comm); 488 inode->i_ino, current->comm);
510 return 0; 489 return 0;
511 } 490 }
512 curr_pos = hash2pos(filp, fname->hash, fname->minor_hash); 491 ctx->pos = hash2pos(file, fname->hash, fname->minor_hash);
513 while (fname) { 492 while (fname) {
514 error = filldir(dirent, fname->name, 493 if (!dir_emit(ctx, fname->name,
515 fname->name_len, curr_pos, 494 fname->name_len,
516 fname->inode, 495 fname->inode,
517 get_dtype(sb, fname->file_type)); 496 get_dtype(sb, fname->file_type))) {
518 if (error) {
519 filp->f_pos = curr_pos;
520 info->extra_fname = fname; 497 info->extra_fname = fname;
521 return error; 498 return 1;
522 } 499 }
523 fname = fname->next; 500 fname = fname->next;
524 } 501 }
525 return 0; 502 return 0;
526} 503}
527 504
528static int ext4_dx_readdir(struct file *filp, 505static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
529 void *dirent, filldir_t filldir)
530{ 506{
531 struct dir_private_info *info = filp->private_data; 507 struct dir_private_info *info = file->private_data;
532 struct inode *inode = file_inode(filp); 508 struct inode *inode = file_inode(file);
533 struct fname *fname; 509 struct fname *fname;
534 int ret; 510 int ret;
535 511
536 if (!info) { 512 if (!info) {
537 info = ext4_htree_create_dir_info(filp, filp->f_pos); 513 info = ext4_htree_create_dir_info(file, ctx->pos);
538 if (!info) 514 if (!info)
539 return -ENOMEM; 515 return -ENOMEM;
540 filp->private_data = info; 516 file->private_data = info;
541 } 517 }
542 518
543 if (filp->f_pos == ext4_get_htree_eof(filp)) 519 if (ctx->pos == ext4_get_htree_eof(file))
544 return 0; /* EOF */ 520 return 0; /* EOF */
545 521
546 /* Some one has messed with f_pos; reset the world */ 522 /* Some one has messed with f_pos; reset the world */
547 if (info->last_pos != filp->f_pos) { 523 if (info->last_pos != ctx->pos) {
548 free_rb_tree_fname(&info->root); 524 free_rb_tree_fname(&info->root);
549 info->curr_node = NULL; 525 info->curr_node = NULL;
550 info->extra_fname = NULL; 526 info->extra_fname = NULL;
551 info->curr_hash = pos2maj_hash(filp, filp->f_pos); 527 info->curr_hash = pos2maj_hash(file, ctx->pos);
552 info->curr_minor_hash = pos2min_hash(filp, filp->f_pos); 528 info->curr_minor_hash = pos2min_hash(file, ctx->pos);
553 } 529 }
554 530
555 /* 531 /*
@@ -557,7 +533,7 @@ static int ext4_dx_readdir(struct file *filp,
557 * chain, return them first. 533 * chain, return them first.
558 */ 534 */
559 if (info->extra_fname) { 535 if (info->extra_fname) {
560 if (call_filldir(filp, dirent, filldir, info->extra_fname)) 536 if (call_filldir(file, ctx, info->extra_fname))
561 goto finished; 537 goto finished;
562 info->extra_fname = NULL; 538 info->extra_fname = NULL;
563 goto next_node; 539 goto next_node;
@@ -571,17 +547,17 @@ static int ext4_dx_readdir(struct file *filp,
571 * cached entries. 547 * cached entries.
572 */ 548 */
573 if ((!info->curr_node) || 549 if ((!info->curr_node) ||
574 (filp->f_version != inode->i_version)) { 550 (file->f_version != inode->i_version)) {
575 info->curr_node = NULL; 551 info->curr_node = NULL;
576 free_rb_tree_fname(&info->root); 552 free_rb_tree_fname(&info->root);
577 filp->f_version = inode->i_version; 553 file->f_version = inode->i_version;
578 ret = ext4_htree_fill_tree(filp, info->curr_hash, 554 ret = ext4_htree_fill_tree(file, info->curr_hash,
579 info->curr_minor_hash, 555 info->curr_minor_hash,
580 &info->next_hash); 556 &info->next_hash);
581 if (ret < 0) 557 if (ret < 0)
582 return ret; 558 return ret;
583 if (ret == 0) { 559 if (ret == 0) {
584 filp->f_pos = ext4_get_htree_eof(filp); 560 ctx->pos = ext4_get_htree_eof(file);
585 break; 561 break;
586 } 562 }
587 info->curr_node = rb_first(&info->root); 563 info->curr_node = rb_first(&info->root);
@@ -590,7 +566,7 @@ static int ext4_dx_readdir(struct file *filp,
590 fname = rb_entry(info->curr_node, struct fname, rb_hash); 566 fname = rb_entry(info->curr_node, struct fname, rb_hash);
591 info->curr_hash = fname->hash; 567 info->curr_hash = fname->hash;
592 info->curr_minor_hash = fname->minor_hash; 568 info->curr_minor_hash = fname->minor_hash;
593 if (call_filldir(filp, dirent, filldir, fname)) 569 if (call_filldir(file, ctx, fname))
594 break; 570 break;
595 next_node: 571 next_node:
596 info->curr_node = rb_next(info->curr_node); 572 info->curr_node = rb_next(info->curr_node);
@@ -601,7 +577,7 @@ static int ext4_dx_readdir(struct file *filp,
601 info->curr_minor_hash = fname->minor_hash; 577 info->curr_minor_hash = fname->minor_hash;
602 } else { 578 } else {
603 if (info->next_hash == ~0) { 579 if (info->next_hash == ~0) {
604 filp->f_pos = ext4_get_htree_eof(filp); 580 ctx->pos = ext4_get_htree_eof(file);
605 break; 581 break;
606 } 582 }
607 info->curr_hash = info->next_hash; 583 info->curr_hash = info->next_hash;
@@ -609,7 +585,7 @@ static int ext4_dx_readdir(struct file *filp,
609 } 585 }
610 } 586 }
611finished: 587finished:
612 info->last_pos = filp->f_pos; 588 info->last_pos = ctx->pos;
613 return 0; 589 return 0;
614} 590}
615 591
@@ -624,7 +600,7 @@ static int ext4_release_dir(struct inode *inode, struct file *filp)
624const struct file_operations ext4_dir_operations = { 600const struct file_operations ext4_dir_operations = {
625 .llseek = ext4_dir_llseek, 601 .llseek = ext4_dir_llseek,
626 .read = generic_read_dir, 602 .read = generic_read_dir,
627 .readdir = ext4_readdir, 603 .iterate = ext4_readdir,
628 .unlocked_ioctl = ext4_ioctl, 604 .unlocked_ioctl = ext4_ioctl,
629#ifdef CONFIG_COMPAT 605#ifdef CONFIG_COMPAT
630 .compat_ioctl = ext4_compat_ioctl, 606 .compat_ioctl = ext4_compat_ioctl,
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 5aae3d12d400..4af03ea84aa3 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2515,7 +2515,7 @@ extern int ext4_try_create_inline_dir(handle_t *handle,
2515 struct inode *parent, 2515 struct inode *parent,
2516 struct inode *inode); 2516 struct inode *inode);
2517extern int ext4_read_inline_dir(struct file *filp, 2517extern int ext4_read_inline_dir(struct file *filp,
2518 void *dirent, filldir_t filldir, 2518 struct dir_context *ctx,
2519 int *has_inline_data); 2519 int *has_inline_data);
2520extern int htree_inlinedir_to_tree(struct file *dir_file, 2520extern int htree_inlinedir_to_tree(struct file *dir_file,
2521 struct inode *dir, ext4_lblk_t block, 2521 struct inode *dir, ext4_lblk_t block,
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 3e2bf873e8a8..1a346a6bdc8f 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1404,16 +1404,15 @@ out:
1404 * offset as if '.' and '..' really take place. 1404 * offset as if '.' and '..' really take place.
1405 * 1405 *
1406 */ 1406 */
1407int ext4_read_inline_dir(struct file *filp, 1407int ext4_read_inline_dir(struct file *file,
1408 void *dirent, filldir_t filldir, 1408 struct dir_context *ctx,
1409 int *has_inline_data) 1409 int *has_inline_data)
1410{ 1410{
1411 int error = 0;
1412 unsigned int offset, parent_ino; 1411 unsigned int offset, parent_ino;
1413 int i, stored; 1412 int i;
1414 struct ext4_dir_entry_2 *de; 1413 struct ext4_dir_entry_2 *de;
1415 struct super_block *sb; 1414 struct super_block *sb;
1416 struct inode *inode = file_inode(filp); 1415 struct inode *inode = file_inode(file);
1417 int ret, inline_size = 0; 1416 int ret, inline_size = 0;
1418 struct ext4_iloc iloc; 1417 struct ext4_iloc iloc;
1419 void *dir_buf = NULL; 1418 void *dir_buf = NULL;
@@ -1444,9 +1443,8 @@ int ext4_read_inline_dir(struct file *filp,
1444 goto out; 1443 goto out;
1445 1444
1446 sb = inode->i_sb; 1445 sb = inode->i_sb;
1447 stored = 0;
1448 parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); 1446 parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
1449 offset = filp->f_pos; 1447 offset = ctx->pos;
1450 1448
1451 /* 1449 /*
1452 * dotdot_offset and dotdot_size is the real offset and 1450 * dotdot_offset and dotdot_size is the real offset and
@@ -1460,104 +1458,74 @@ int ext4_read_inline_dir(struct file *filp,
1460 extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE; 1458 extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;
1461 extra_size = extra_offset + inline_size; 1459 extra_size = extra_offset + inline_size;
1462 1460
1463 while (!error && !stored && filp->f_pos < extra_size) { 1461 /*
1464revalidate: 1462 * If the version has changed since the last call to
1465 /* 1463 * readdir(2), then we might be pointing to an invalid
1466 * If the version has changed since the last call to 1464 * dirent right now. Scan from the start of the inline
1467 * readdir(2), then we might be pointing to an invalid 1465 * dir to make sure.
1468 * dirent right now. Scan from the start of the inline 1466 */
1469 * dir to make sure. 1467 if (file->f_version != inode->i_version) {
1470 */ 1468 for (i = 0; i < extra_size && i < offset;) {
1471 if (filp->f_version != inode->i_version) { 1469 /*
1472 for (i = 0; i < extra_size && i < offset;) { 1470 * "." is with offset 0 and
1473 /* 1471 * ".." is dotdot_offset.
1474 * "." is with offset 0 and 1472 */
1475 * ".." is dotdot_offset. 1473 if (!i) {
1476 */ 1474 i = dotdot_offset;
1477 if (!i) { 1475 continue;
1478 i = dotdot_offset; 1476 } else if (i == dotdot_offset) {
1479 continue; 1477 i = dotdot_size;
1480 } else if (i == dotdot_offset) {
1481 i = dotdot_size;
1482 continue;
1483 }
1484 /* for other entry, the real offset in
1485 * the buf has to be tuned accordingly.
1486 */
1487 de = (struct ext4_dir_entry_2 *)
1488 (dir_buf + i - extra_offset);
1489 /* It's too expensive to do a full
1490 * dirent test each time round this
1491 * loop, but we do have to test at
1492 * least that it is non-zero. A
1493 * failure will be detected in the
1494 * dirent test below. */
1495 if (ext4_rec_len_from_disk(de->rec_len,
1496 extra_size) < EXT4_DIR_REC_LEN(1))
1497 break;
1498 i += ext4_rec_len_from_disk(de->rec_len,
1499 extra_size);
1500 }
1501 offset = i;
1502 filp->f_pos = offset;
1503 filp->f_version = inode->i_version;
1504 }
1505
1506 while (!error && filp->f_pos < extra_size) {
1507 if (filp->f_pos == 0) {
1508 error = filldir(dirent, ".", 1, 0, inode->i_ino,
1509 DT_DIR);
1510 if (error)
1511 break;
1512 stored++;
1513 filp->f_pos = dotdot_offset;
1514 continue; 1478 continue;
1515 } 1479 }
1480 /* for other entry, the real offset in
1481 * the buf has to be tuned accordingly.
1482 */
1483 de = (struct ext4_dir_entry_2 *)
1484 (dir_buf + i - extra_offset);
1485 /* It's too expensive to do a full
1486 * dirent test each time round this
1487 * loop, but we do have to test at
1488 * least that it is non-zero. A
1489 * failure will be detected in the
1490 * dirent test below. */
1491 if (ext4_rec_len_from_disk(de->rec_len, extra_size)
1492 < EXT4_DIR_REC_LEN(1))
1493 break;
1494 i += ext4_rec_len_from_disk(de->rec_len,
1495 extra_size);
1496 }
1497 offset = i;
1498 ctx->pos = offset;
1499 file->f_version = inode->i_version;
1500 }
1516 1501
1517 if (filp->f_pos == dotdot_offset) { 1502 while (ctx->pos < extra_size) {
1518 error = filldir(dirent, "..", 2, 1503 if (ctx->pos == 0) {
1519 dotdot_offset, 1504 if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
1520 parent_ino, DT_DIR); 1505 goto out;
1521 if (error) 1506 ctx->pos = dotdot_offset;
1522 break; 1507 continue;
1523 stored++; 1508 }
1524 1509
1525 filp->f_pos = dotdot_size; 1510 if (ctx->pos == dotdot_offset) {
1526 continue; 1511 if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR))
1527 } 1512 goto out;
1513 ctx->pos = dotdot_size;
1514 continue;
1515 }
1528 1516
1529 de = (struct ext4_dir_entry_2 *) 1517 de = (struct ext4_dir_entry_2 *)
1530 (dir_buf + filp->f_pos - extra_offset); 1518 (dir_buf + ctx->pos - extra_offset);
1531 if (ext4_check_dir_entry(inode, filp, de, 1519 if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf,
1532 iloc.bh, dir_buf, 1520 extra_size, ctx->pos))
1533 extra_size, filp->f_pos)) { 1521 goto out;
1534 ret = stored; 1522 if (le32_to_cpu(de->inode)) {
1523 if (!dir_emit(ctx, de->name, de->name_len,
1524 le32_to_cpu(de->inode),
1525 get_dtype(sb, de->file_type)))
1535 goto out; 1526 goto out;
1536 }
1537 if (le32_to_cpu(de->inode)) {
1538 /* We might block in the next section
1539 * if the data destination is
1540 * currently swapped out. So, use a
1541 * version stamp to detect whether or
1542 * not the directory has been modified
1543 * during the copy operation.
1544 */
1545 u64 version = filp->f_version;
1546
1547 error = filldir(dirent, de->name,
1548 de->name_len,
1549 filp->f_pos,
1550 le32_to_cpu(de->inode),
1551 get_dtype(sb, de->file_type));
1552 if (error)
1553 break;
1554 if (version != filp->f_version)
1555 goto revalidate;
1556 stored++;
1557 }
1558 filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
1559 extra_size);
1560 } 1527 }
1528 ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size);
1561 } 1529 }
1562out: 1530out:
1563 kfree(dir_buf); 1531 kfree(dir_buf);