diff options
Diffstat (limited to 'fs/ext3')
-rw-r--r-- | fs/ext3/dir.c | 157 | ||||
-rw-r--r-- | fs/ext3/fsync.c | 8 | ||||
-rw-r--r-- | fs/ext3/inode.c | 10 | ||||
-rw-r--r-- | fs/ext3/namei.c | 54 | ||||
-rw-r--r-- | fs/ext3/super.c | 13 |
5 files changed, 136 insertions, 106 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 | ||
31 | static int ext3_dx_readdir(struct file * filp, | 31 | static int ext3_dx_readdir(struct file *, struct dir_context *); |
32 | void * dirent, filldir_t filldir); | ||
33 | 32 | ||
34 | static unsigned char get_dtype(struct super_block *sb, int filetype) | 33 | static 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 | ||
94 | static int ext3_readdir(struct file * filp, | 93 | static 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 | ||
159 | revalidate: | ||
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 | } |
225 | out: | 205 | return 0; |
226 | return ret; | ||
227 | } | 206 | } |
228 | 207 | ||
229 | static inline int is_32bit_api(void) | 208 | static 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 | */ |
455 | static int call_filldir(struct file * filp, void * dirent, | 434 | static 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 | ||
486 | static int ext3_dx_readdir(struct file * filp, | 458 | static 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 | } |
569 | finished: | 540 | finished: |
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) | |||
582 | const struct file_operations ext3_dir_operations = { | 553 | const 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/fs/ext3/fsync.c b/fs/ext3/fsync.c index b31dbd4c46ad..1cb9c7e10c6f 100644 --- a/fs/ext3/fsync.c +++ b/fs/ext3/fsync.c | |||
@@ -48,9 +48,13 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | |||
48 | 48 | ||
49 | trace_ext3_sync_file_enter(file, datasync); | 49 | trace_ext3_sync_file_enter(file, datasync); |
50 | 50 | ||
51 | if (inode->i_sb->s_flags & MS_RDONLY) | 51 | if (inode->i_sb->s_flags & MS_RDONLY) { |
52 | /* Make sure that we read updated state */ | ||
53 | smp_rmb(); | ||
54 | if (EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS) | ||
55 | return -EROFS; | ||
52 | return 0; | 56 | return 0; |
53 | 57 | } | |
54 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | 58 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); |
55 | if (ret) | 59 | if (ret) |
56 | goto out; | 60 | goto out; |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 23c712825640..2bd85486b879 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -1825,19 +1825,20 @@ ext3_readpages(struct file *file, struct address_space *mapping, | |||
1825 | return mpage_readpages(mapping, pages, nr_pages, ext3_get_block); | 1825 | return mpage_readpages(mapping, pages, nr_pages, ext3_get_block); |
1826 | } | 1826 | } |
1827 | 1827 | ||
1828 | static void ext3_invalidatepage(struct page *page, unsigned long offset) | 1828 | static void ext3_invalidatepage(struct page *page, unsigned int offset, |
1829 | unsigned int length) | ||
1829 | { | 1830 | { |
1830 | journal_t *journal = EXT3_JOURNAL(page->mapping->host); | 1831 | journal_t *journal = EXT3_JOURNAL(page->mapping->host); |
1831 | 1832 | ||
1832 | trace_ext3_invalidatepage(page, offset); | 1833 | trace_ext3_invalidatepage(page, offset, length); |
1833 | 1834 | ||
1834 | /* | 1835 | /* |
1835 | * If it's a full truncate we just forget about the pending dirtying | 1836 | * If it's a full truncate we just forget about the pending dirtying |
1836 | */ | 1837 | */ |
1837 | if (offset == 0) | 1838 | if (offset == 0 && length == PAGE_CACHE_SIZE) |
1838 | ClearPageChecked(page); | 1839 | ClearPageChecked(page); |
1839 | 1840 | ||
1840 | journal_invalidatepage(journal, page, offset); | 1841 | journal_invalidatepage(journal, page, offset, length); |
1841 | } | 1842 | } |
1842 | 1843 | ||
1843 | static int ext3_releasepage(struct page *page, gfp_t wait) | 1844 | static int ext3_releasepage(struct page *page, gfp_t wait) |
@@ -1984,6 +1985,7 @@ static const struct address_space_operations ext3_ordered_aops = { | |||
1984 | .direct_IO = ext3_direct_IO, | 1985 | .direct_IO = ext3_direct_IO, |
1985 | .migratepage = buffer_migrate_page, | 1986 | .migratepage = buffer_migrate_page, |
1986 | .is_partially_uptodate = block_is_partially_uptodate, | 1987 | .is_partially_uptodate = block_is_partially_uptodate, |
1988 | .is_dirty_writeback = buffer_check_dirty_writeback, | ||
1987 | .error_remove_page = generic_error_remove_page, | 1989 | .error_remove_page = generic_error_remove_page, |
1988 | }; | 1990 | }; |
1989 | 1991 | ||
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 692de13e3596..1194b1f0f839 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
@@ -576,11 +576,8 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
576 | if (!ext3_check_dir_entry("htree_dirblock_to_tree", dir, de, bh, | 576 | if (!ext3_check_dir_entry("htree_dirblock_to_tree", dir, de, bh, |
577 | (block<<EXT3_BLOCK_SIZE_BITS(dir->i_sb)) | 577 | (block<<EXT3_BLOCK_SIZE_BITS(dir->i_sb)) |
578 | +((char *)de - bh->b_data))) { | 578 | +((char *)de - bh->b_data))) { |
579 | /* On error, skip the f_pos to the next block. */ | 579 | /* silently ignore the rest of the block */ |
580 | dir_file->f_pos = (dir_file->f_pos | | 580 | break; |
581 | (dir->i_sb->s_blocksize - 1)) + 1; | ||
582 | brelse (bh); | ||
583 | return count; | ||
584 | } | 581 | } |
585 | ext3fs_dirhash(de->name, de->name_len, hinfo); | 582 | ext3fs_dirhash(de->name, de->name_len, hinfo); |
586 | if ((hinfo->hash < start_hash) || | 583 | if ((hinfo->hash < start_hash) || |
@@ -1762,6 +1759,45 @@ retry: | |||
1762 | return err; | 1759 | return err; |
1763 | } | 1760 | } |
1764 | 1761 | ||
1762 | static int ext3_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) | ||
1763 | { | ||
1764 | handle_t *handle; | ||
1765 | struct inode *inode; | ||
1766 | int err, retries = 0; | ||
1767 | |||
1768 | dquot_initialize(dir); | ||
1769 | |||
1770 | retry: | ||
1771 | handle = ext3_journal_start(dir, EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) + | ||
1772 | 4 + EXT3_XATTR_TRANS_BLOCKS); | ||
1773 | |||
1774 | if (IS_ERR(handle)) | ||
1775 | return PTR_ERR(handle); | ||
1776 | |||
1777 | inode = ext3_new_inode (handle, dir, NULL, mode); | ||
1778 | err = PTR_ERR(inode); | ||
1779 | if (!IS_ERR(inode)) { | ||
1780 | inode->i_op = &ext3_file_inode_operations; | ||
1781 | inode->i_fop = &ext3_file_operations; | ||
1782 | ext3_set_aops(inode); | ||
1783 | d_tmpfile(dentry, inode); | ||
1784 | err = ext3_orphan_add(handle, inode); | ||
1785 | if (err) | ||
1786 | goto err_drop_inode; | ||
1787 | mark_inode_dirty(inode); | ||
1788 | unlock_new_inode(inode); | ||
1789 | } | ||
1790 | ext3_journal_stop(handle); | ||
1791 | if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) | ||
1792 | goto retry; | ||
1793 | return err; | ||
1794 | err_drop_inode: | ||
1795 | ext3_journal_stop(handle); | ||
1796 | unlock_new_inode(inode); | ||
1797 | iput(inode); | ||
1798 | return err; | ||
1799 | } | ||
1800 | |||
1765 | static int ext3_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) | 1801 | static int ext3_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) |
1766 | { | 1802 | { |
1767 | handle_t *handle; | 1803 | handle_t *handle; |
@@ -2303,7 +2339,7 @@ static int ext3_link (struct dentry * old_dentry, | |||
2303 | 2339 | ||
2304 | retry: | 2340 | retry: |
2305 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + | 2341 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
2306 | EXT3_INDEX_EXTRA_TRANS_BLOCKS); | 2342 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1); |
2307 | if (IS_ERR(handle)) | 2343 | if (IS_ERR(handle)) |
2308 | return PTR_ERR(handle); | 2344 | return PTR_ERR(handle); |
2309 | 2345 | ||
@@ -2317,6 +2353,11 @@ retry: | |||
2317 | err = ext3_add_entry(handle, dentry, inode); | 2353 | err = ext3_add_entry(handle, dentry, inode); |
2318 | if (!err) { | 2354 | if (!err) { |
2319 | ext3_mark_inode_dirty(handle, inode); | 2355 | ext3_mark_inode_dirty(handle, inode); |
2356 | /* this can happen only for tmpfile being | ||
2357 | * linked the first time | ||
2358 | */ | ||
2359 | if (inode->i_nlink == 1) | ||
2360 | ext3_orphan_del(handle, inode); | ||
2320 | d_instantiate(dentry, inode); | 2361 | d_instantiate(dentry, inode); |
2321 | } else { | 2362 | } else { |
2322 | drop_nlink(inode); | 2363 | drop_nlink(inode); |
@@ -2519,6 +2560,7 @@ const struct inode_operations ext3_dir_inode_operations = { | |||
2519 | .mkdir = ext3_mkdir, | 2560 | .mkdir = ext3_mkdir, |
2520 | .rmdir = ext3_rmdir, | 2561 | .rmdir = ext3_rmdir, |
2521 | .mknod = ext3_mknod, | 2562 | .mknod = ext3_mknod, |
2563 | .tmpfile = ext3_tmpfile, | ||
2522 | .rename = ext3_rename, | 2564 | .rename = ext3_rename, |
2523 | .setattr = ext3_setattr, | 2565 | .setattr = ext3_setattr, |
2524 | #ifdef CONFIG_EXT3_FS_XATTR | 2566 | #ifdef CONFIG_EXT3_FS_XATTR |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 6356665a74bb..c47f14750722 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -174,6 +174,11 @@ static void ext3_handle_error(struct super_block *sb) | |||
174 | if (test_opt (sb, ERRORS_RO)) { | 174 | if (test_opt (sb, ERRORS_RO)) { |
175 | ext3_msg(sb, KERN_CRIT, | 175 | ext3_msg(sb, KERN_CRIT, |
176 | "error: remounting filesystem read-only"); | 176 | "error: remounting filesystem read-only"); |
177 | /* | ||
178 | * Make sure updated value of ->s_mount_state will be visible | ||
179 | * before ->s_flags update. | ||
180 | */ | ||
181 | smp_wmb(); | ||
177 | sb->s_flags |= MS_RDONLY; | 182 | sb->s_flags |= MS_RDONLY; |
178 | } | 183 | } |
179 | ext3_commit_super(sb, es, 1); | 184 | ext3_commit_super(sb, es, 1); |
@@ -291,8 +296,14 @@ void ext3_abort(struct super_block *sb, const char *function, | |||
291 | ext3_msg(sb, KERN_CRIT, | 296 | ext3_msg(sb, KERN_CRIT, |
292 | "error: remounting filesystem read-only"); | 297 | "error: remounting filesystem read-only"); |
293 | EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; | 298 | EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; |
294 | sb->s_flags |= MS_RDONLY; | ||
295 | set_opt(EXT3_SB(sb)->s_mount_opt, ABORT); | 299 | set_opt(EXT3_SB(sb)->s_mount_opt, ABORT); |
300 | /* | ||
301 | * Make sure updated value of ->s_mount_state will be visible | ||
302 | * before ->s_flags update. | ||
303 | */ | ||
304 | smp_wmb(); | ||
305 | sb->s_flags |= MS_RDONLY; | ||
306 | |||
296 | if (EXT3_SB(sb)->s_journal) | 307 | if (EXT3_SB(sb)->s_journal) |
297 | journal_abort(EXT3_SB(sb)->s_journal, -EIO); | 308 | journal_abort(EXT3_SB(sb)->s_journal, -EIO); |
298 | } | 309 | } |