aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext3
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext3')
-rw-r--r--fs/ext3/Makefile2
-rw-r--r--fs/ext3/balloc.c31
-rw-r--r--fs/ext3/dir.c3
-rw-r--r--fs/ext3/ext3_jbd.c59
-rw-r--r--fs/ext3/inode.c85
-rw-r--r--fs/ext3/namei.c9
-rw-r--r--fs/ext3/super.c17
-rw-r--r--fs/ext3/xattr.c5
8 files changed, 179 insertions, 32 deletions
diff --git a/fs/ext3/Makefile b/fs/ext3/Makefile
index 704cd44a40c2..e77766a8b3f0 100644
--- a/fs/ext3/Makefile
+++ b/fs/ext3/Makefile
@@ -5,7 +5,7 @@
5obj-$(CONFIG_EXT3_FS) += ext3.o 5obj-$(CONFIG_EXT3_FS) += ext3.o
6 6
7ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ 7ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
8 ioctl.o namei.o super.o symlink.o hash.o resize.o 8 ioctl.o namei.o super.o symlink.o hash.o resize.o ext3_jbd.o
9 9
10ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o 10ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
11ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o 11ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index b41a7d7e20f0..22161740ba29 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -144,7 +144,7 @@ restart:
144 144
145 printk("Block Allocation Reservation Windows Map (%s):\n", fn); 145 printk("Block Allocation Reservation Windows Map (%s):\n", fn);
146 while (n) { 146 while (n) {
147 rsv = list_entry(n, struct ext3_reserve_window_node, rsv_node); 147 rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node);
148 if (verbose) 148 if (verbose)
149 printk("reservation window 0x%p " 149 printk("reservation window 0x%p "
150 "start: %lu, end: %lu\n", 150 "start: %lu, end: %lu\n",
@@ -730,7 +730,7 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
730 here = 0; 730 here = 0;
731 731
732 p = ((char *)bh->b_data) + (here >> 3); 732 p = ((char *)bh->b_data) + (here >> 3);
733 r = memscan(p, 0, (maxblocks - here + 7) >> 3); 733 r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3));
734 next = (r - ((char *)bh->b_data)) << 3; 734 next = (r - ((char *)bh->b_data)) << 3;
735 735
736 if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh)) 736 if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh))
@@ -949,7 +949,7 @@ static int find_next_reservable_window(
949 949
950 prev = rsv; 950 prev = rsv;
951 next = rb_next(&rsv->rsv_node); 951 next = rb_next(&rsv->rsv_node);
952 rsv = list_entry(next,struct ext3_reserve_window_node,rsv_node); 952 rsv = rb_entry(next,struct ext3_reserve_window_node,rsv_node);
953 953
954 /* 954 /*
955 * Reached the last reservation, we can just append to the 955 * Reached the last reservation, we can just append to the
@@ -1148,7 +1148,7 @@ retry:
1148 * check if the first free block is within the 1148 * check if the first free block is within the
1149 * free space we just reserved 1149 * free space we just reserved
1150 */ 1150 */
1151 if (start_block >= my_rsv->rsv_start && start_block < my_rsv->rsv_end) 1151 if (start_block >= my_rsv->rsv_start && start_block <= my_rsv->rsv_end)
1152 return 0; /* success */ 1152 return 0; /* success */
1153 /* 1153 /*
1154 * if the first free bit we found is out of the reservable space 1154 * if the first free bit we found is out of the reservable space
@@ -1193,7 +1193,7 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
1193 if (!next) 1193 if (!next)
1194 my_rsv->rsv_end += size; 1194 my_rsv->rsv_end += size;
1195 else { 1195 else {
1196 next_rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node); 1196 next_rsv = rb_entry(next, struct ext3_reserve_window_node, rsv_node);
1197 1197
1198 if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size) 1198 if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size)
1199 my_rsv->rsv_end += size; 1199 my_rsv->rsv_end += size;
@@ -1271,7 +1271,7 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
1271 } 1271 }
1272 /* 1272 /*
1273 * grp_goal is a group relative block number (if there is a goal) 1273 * grp_goal is a group relative block number (if there is a goal)
1274 * 0 < grp_goal < EXT3_BLOCKS_PER_GROUP(sb) 1274 * 0 <= grp_goal < EXT3_BLOCKS_PER_GROUP(sb)
1275 * first block is a filesystem wide block number 1275 * first block is a filesystem wide block number
1276 * first block is the block number of the first block in this group 1276 * first block is the block number of the first block in this group
1277 */ 1277 */
@@ -1307,10 +1307,14 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
1307 if (!goal_in_my_reservation(&my_rsv->rsv_window, 1307 if (!goal_in_my_reservation(&my_rsv->rsv_window,
1308 grp_goal, group, sb)) 1308 grp_goal, group, sb))
1309 grp_goal = -1; 1309 grp_goal = -1;
1310 } else if (grp_goal > 0 && 1310 } else if (grp_goal >= 0) {
1311 (my_rsv->rsv_end-grp_goal+1) < *count) 1311 int curr = my_rsv->rsv_end -
1312 try_to_extend_reservation(my_rsv, sb, 1312 (grp_goal + group_first_block) + 1;
1313 *count-my_rsv->rsv_end + grp_goal - 1); 1313
1314 if (curr < *count)
1315 try_to_extend_reservation(my_rsv, sb,
1316 *count - curr);
1317 }
1314 1318
1315 if ((my_rsv->rsv_start > group_last_block) || 1319 if ((my_rsv->rsv_start > group_last_block) ||
1316 (my_rsv->rsv_end < group_first_block)) { 1320 (my_rsv->rsv_end < group_first_block)) {
@@ -1511,10 +1515,8 @@ retry_alloc:
1511 if (group_no >= ngroups) 1515 if (group_no >= ngroups)
1512 group_no = 0; 1516 group_no = 0;
1513 gdp = ext3_get_group_desc(sb, group_no, &gdp_bh); 1517 gdp = ext3_get_group_desc(sb, group_no, &gdp_bh);
1514 if (!gdp) { 1518 if (!gdp)
1515 *errp = -EIO; 1519 goto io_error;
1516 goto out;
1517 }
1518 free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); 1520 free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
1519 /* 1521 /*
1520 * skip this group if the number of 1522 * skip this group if the number of
@@ -1548,6 +1550,7 @@ retry_alloc:
1548 */ 1550 */
1549 if (my_rsv) { 1551 if (my_rsv) {
1550 my_rsv = NULL; 1552 my_rsv = NULL;
1553 windowsz = 0;
1551 group_no = goal_group; 1554 group_no = goal_group;
1552 goto retry_alloc; 1555 goto retry_alloc;
1553 } 1556 }
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index d0b54f30b914..5a9313ecd4ef 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -154,6 +154,9 @@ static int ext3_readdir(struct file * filp,
154 ext3_error (sb, "ext3_readdir", 154 ext3_error (sb, "ext3_readdir",
155 "directory #%lu contains a hole at offset %lu", 155 "directory #%lu contains a hole at offset %lu",
156 inode->i_ino, (unsigned long)filp->f_pos); 156 inode->i_ino, (unsigned long)filp->f_pos);
157 /* corrupt size? Maybe no more blocks to read */
158 if (filp->f_pos > inode->i_blocks << 9)
159 break;
157 filp->f_pos += sb->s_blocksize - offset; 160 filp->f_pos += sb->s_blocksize - offset;
158 continue; 161 continue;
159 } 162 }
diff --git a/fs/ext3/ext3_jbd.c b/fs/ext3/ext3_jbd.c
new file mode 100644
index 000000000000..e1f91fd26a93
--- /dev/null
+++ b/fs/ext3/ext3_jbd.c
@@ -0,0 +1,59 @@
1/*
2 * Interface between ext3 and JBD
3 */
4
5#include <linux/ext3_jbd.h>
6
7int __ext3_journal_get_undo_access(const char *where, handle_t *handle,
8 struct buffer_head *bh)
9{
10 int err = journal_get_undo_access(handle, bh);
11 if (err)
12 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
13 return err;
14}
15
16int __ext3_journal_get_write_access(const char *where, handle_t *handle,
17 struct buffer_head *bh)
18{
19 int err = journal_get_write_access(handle, bh);
20 if (err)
21 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
22 return err;
23}
24
25int __ext3_journal_forget(const char *where, handle_t *handle,
26 struct buffer_head *bh)
27{
28 int err = journal_forget(handle, bh);
29 if (err)
30 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
31 return err;
32}
33
34int __ext3_journal_revoke(const char *where, handle_t *handle,
35 unsigned long blocknr, struct buffer_head *bh)
36{
37 int err = journal_revoke(handle, blocknr, bh);
38 if (err)
39 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
40 return err;
41}
42
43int __ext3_journal_get_create_access(const char *where,
44 handle_t *handle, struct buffer_head *bh)
45{
46 int err = journal_get_create_access(handle, bh);
47 if (err)
48 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
49 return err;
50}
51
52int __ext3_journal_dirty_metadata(const char *where,
53 handle_t *handle, struct buffer_head *bh)
54{
55 int err = journal_dirty_metadata(handle, bh);
56 if (err)
57 ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
58 return err;
59}
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 03ba5bcab186..beaf25f5112f 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1148,37 +1148,102 @@ static int do_journal_get_write_access(handle_t *handle,
1148 return ext3_journal_get_write_access(handle, bh); 1148 return ext3_journal_get_write_access(handle, bh);
1149} 1149}
1150 1150
1151/*
1152 * The idea of this helper function is following:
1153 * if prepare_write has allocated some blocks, but not all of them, the
1154 * transaction must include the content of the newly allocated blocks.
1155 * This content is expected to be set to zeroes by block_prepare_write().
1156 * 2006/10/14 SAW
1157 */
1158static int ext3_prepare_failure(struct file *file, struct page *page,
1159 unsigned from, unsigned to)
1160{
1161 struct address_space *mapping;
1162 struct buffer_head *bh, *head, *next;
1163 unsigned block_start, block_end;
1164 unsigned blocksize;
1165 int ret;
1166 handle_t *handle = ext3_journal_current_handle();
1167
1168 mapping = page->mapping;
1169 if (ext3_should_writeback_data(mapping->host)) {
1170 /* optimization: no constraints about data */
1171skip:
1172 return ext3_journal_stop(handle);
1173 }
1174
1175 head = page_buffers(page);
1176 blocksize = head->b_size;
1177 for ( bh = head, block_start = 0;
1178 bh != head || !block_start;
1179 block_start = block_end, bh = next)
1180 {
1181 next = bh->b_this_page;
1182 block_end = block_start + blocksize;
1183 if (block_end <= from)
1184 continue;
1185 if (block_start >= to) {
1186 block_start = to;
1187 break;
1188 }
1189 if (!buffer_mapped(bh))
1190 /* prepare_write failed on this bh */
1191 break;
1192 if (ext3_should_journal_data(mapping->host)) {
1193 ret = do_journal_get_write_access(handle, bh);
1194 if (ret) {
1195 ext3_journal_stop(handle);
1196 return ret;
1197 }
1198 }
1199 /*
1200 * block_start here becomes the first block where the current iteration
1201 * of prepare_write failed.
1202 */
1203 }
1204 if (block_start <= from)
1205 goto skip;
1206
1207 /* commit allocated and zeroed buffers */
1208 return mapping->a_ops->commit_write(file, page, from, block_start);
1209}
1210
1151static int ext3_prepare_write(struct file *file, struct page *page, 1211static int ext3_prepare_write(struct file *file, struct page *page,
1152 unsigned from, unsigned to) 1212 unsigned from, unsigned to)
1153{ 1213{
1154 struct inode *inode = page->mapping->host; 1214 struct inode *inode = page->mapping->host;
1155 int ret, needed_blocks = ext3_writepage_trans_blocks(inode); 1215 int ret, ret2;
1216 int needed_blocks = ext3_writepage_trans_blocks(inode);
1156 handle_t *handle; 1217 handle_t *handle;
1157 int retries = 0; 1218 int retries = 0;
1158 1219
1159retry: 1220retry:
1160 handle = ext3_journal_start(inode, needed_blocks); 1221 handle = ext3_journal_start(inode, needed_blocks);
1161 if (IS_ERR(handle)) { 1222 if (IS_ERR(handle))
1162 ret = PTR_ERR(handle); 1223 return PTR_ERR(handle);
1163 goto out;
1164 }
1165 if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) 1224 if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode))
1166 ret = nobh_prepare_write(page, from, to, ext3_get_block); 1225 ret = nobh_prepare_write(page, from, to, ext3_get_block);
1167 else 1226 else
1168 ret = block_prepare_write(page, from, to, ext3_get_block); 1227 ret = block_prepare_write(page, from, to, ext3_get_block);
1169 if (ret) 1228 if (ret)
1170 goto prepare_write_failed; 1229 goto failure;
1171 1230
1172 if (ext3_should_journal_data(inode)) { 1231 if (ext3_should_journal_data(inode)) {
1173 ret = walk_page_buffers(handle, page_buffers(page), 1232 ret = walk_page_buffers(handle, page_buffers(page),
1174 from, to, NULL, do_journal_get_write_access); 1233 from, to, NULL, do_journal_get_write_access);
1234 if (ret)
1235 /* fatal error, just put the handle and return */
1236 journal_stop(handle);
1175 } 1237 }
1176prepare_write_failed: 1238 return ret;
1177 if (ret) 1239
1178 ext3_journal_stop(handle); 1240failure:
1241 ret2 = ext3_prepare_failure(file, page, from, to);
1242 if (ret2 < 0)
1243 return ret2;
1179 if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) 1244 if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
1180 goto retry; 1245 goto retry;
1181out: 1246 /* retry number exceeded, or other error like -EDQUOT */
1182 return ret; 1247 return ret;
1183} 1248}
1184 1249
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 906731a20f1a..60d2f9dbdb00 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -552,6 +552,15 @@ static int htree_dirblock_to_tree(struct file *dir_file,
552 dir->i_sb->s_blocksize - 552 dir->i_sb->s_blocksize -
553 EXT3_DIR_REC_LEN(0)); 553 EXT3_DIR_REC_LEN(0));
554 for (; de < top; de = ext3_next_entry(de)) { 554 for (; de < top; de = ext3_next_entry(de)) {
555 if (!ext3_check_dir_entry("htree_dirblock_to_tree", dir, de, bh,
556 (block<<EXT3_BLOCK_SIZE_BITS(dir->i_sb))
557 +((char *)de - bh->b_data))) {
558 /* On error, skip the f_pos to the next block. */
559 dir_file->f_pos = (dir_file->f_pos |
560 (dir->i_sb->s_blocksize - 1)) + 1;
561 brelse (bh);
562 return count;
563 }
555 ext3fs_dirhash(de->name, de->name_len, hinfo); 564 ext3fs_dirhash(de->name, de->name_len, hinfo);
556 if ((hinfo->hash < start_hash) || 565 if ((hinfo->hash < start_hash) ||
557 ((hinfo->hash == start_hash) && 566 ((hinfo->hash == start_hash) &&
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index afc2d4f42d77..580b8a6ca979 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -436,7 +436,7 @@ static void ext3_put_super (struct super_block * sb)
436 return; 436 return;
437} 437}
438 438
439static kmem_cache_t *ext3_inode_cachep; 439static struct kmem_cache *ext3_inode_cachep;
440 440
441/* 441/*
442 * Called inside transaction, so use GFP_NOFS 442 * Called inside transaction, so use GFP_NOFS
@@ -445,7 +445,7 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
445{ 445{
446 struct ext3_inode_info *ei; 446 struct ext3_inode_info *ei;
447 447
448 ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS); 448 ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS);
449 if (!ei) 449 if (!ei)
450 return NULL; 450 return NULL;
451#ifdef CONFIG_EXT3_FS_POSIX_ACL 451#ifdef CONFIG_EXT3_FS_POSIX_ACL
@@ -462,7 +462,7 @@ static void ext3_destroy_inode(struct inode *inode)
462 kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); 462 kmem_cache_free(ext3_inode_cachep, EXT3_I(inode));
463} 463}
464 464
465static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) 465static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
466{ 466{
467 struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; 467 struct ext3_inode_info *ei = (struct ext3_inode_info *) foo;
468 468
@@ -1264,6 +1264,12 @@ static void ext3_orphan_cleanup (struct super_block * sb,
1264 return; 1264 return;
1265 } 1265 }
1266 1266
1267 if (bdev_read_only(sb->s_bdev)) {
1268 printk(KERN_ERR "EXT3-fs: write access "
1269 "unavailable, skipping orphan cleanup.\n");
1270 return;
1271 }
1272
1267 if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) { 1273 if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) {
1268 if (es->s_last_orphan) 1274 if (es->s_last_orphan)
1269 jbd_debug(1, "Errors on filesystem, " 1275 jbd_debug(1, "Errors on filesystem, "
@@ -2387,6 +2393,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
2387 struct ext3_super_block *es = sbi->s_es; 2393 struct ext3_super_block *es = sbi->s_es;
2388 ext3_fsblk_t overhead; 2394 ext3_fsblk_t overhead;
2389 int i; 2395 int i;
2396 u64 fsid;
2390 2397
2391 if (test_opt (sb, MINIX_DF)) 2398 if (test_opt (sb, MINIX_DF))
2392 overhead = 0; 2399 overhead = 0;
@@ -2433,6 +2440,10 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
2433 buf->f_files = le32_to_cpu(es->s_inodes_count); 2440 buf->f_files = le32_to_cpu(es->s_inodes_count);
2434 buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); 2441 buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
2435 buf->f_namelen = EXT3_NAME_LEN; 2442 buf->f_namelen = EXT3_NAME_LEN;
2443 fsid = le64_to_cpup((void *)es->s_uuid) ^
2444 le64_to_cpup((void *)es->s_uuid + sizeof(u64));
2445 buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
2446 buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
2436 return 0; 2447 return 0;
2437} 2448}
2438 2449
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index f86f2482f01d..99857a400f4b 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -459,14 +459,11 @@ static void ext3_xattr_update_super_block(handle_t *handle,
459 if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR)) 459 if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR))
460 return; 460 return;
461 461
462 lock_super(sb);
463 if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) { 462 if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) {
464 EXT3_SB(sb)->s_es->s_feature_compat |= 463 EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR);
465 cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR);
466 sb->s_dirt = 1; 464 sb->s_dirt = 1;
467 ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); 465 ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
468 } 466 }
469 unlock_super(sb);
470} 467}
471 468
472/* 469/*