X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fext3%2Fsuper.c;h=4a970411a458f4534c9c4a09f0c02026a9bbc61e;hb=b51ebdc40cf3a9eb4d3ace48dbd254bb0184481d;hp=440c35d98993a850a6be49d5faf222538f89af4e;hpb=3fc74269c8910573a0e9a7bc303752194ce5cae0;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 440c35d..4a97041 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -47,8 +48,8 @@ static int ext3_load_journal(struct super_block *, struct ext3_super_block *, unsigned long journal_devnum); static int ext3_create_journal(struct super_block *, struct ext3_super_block *, unsigned int); -static void ext3_commit_super (struct super_block * sb, - struct ext3_super_block * es, +static int ext3_commit_super(struct super_block *sb, + struct ext3_super_block *es, int sync); static void ext3_mark_recovery_complete(struct super_block * sb, struct ext3_super_block * es); @@ -59,9 +60,9 @@ static const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]); static int ext3_remount (struct super_block * sb, int * flags, char * data); static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf); -static void ext3_unlockfs(struct super_block *sb); +static int ext3_unfreeze(struct super_block *sb); static void ext3_write_super (struct super_block * sb); -static void ext3_write_super_lockfs(struct super_block *sb); +static int ext3_freeze(struct super_block *sb); /* * Wrappers for journal_start/end. @@ -83,7 +84,7 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) * take the FS itself readonly cleanly. */ journal = EXT3_SB(sb)->s_journal; if (is_journal_aborted(journal)) { - ext3_abort(sb, __FUNCTION__, + ext3_abort(sb, __func__, "Detected aborted journal"); return ERR_PTR(-EROFS); } @@ -280,7 +281,8 @@ void ext3_abort (struct super_block * sb, const char * function, EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; sb->s_flags |= MS_RDONLY; EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; - journal_abort(EXT3_SB(sb)->s_journal, -EIO); + if (EXT3_SB(sb)->s_journal) + journal_abort(EXT3_SB(sb)->s_journal, -EIO); } void ext3_warning (struct super_block * sb, const char * function, @@ -303,7 +305,7 @@ void ext3_update_dynamic_rev(struct super_block *sb) if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV) return; - ext3_warning(sb, __FUNCTION__, + ext3_warning(sb, __func__, "updating to rev %d because of new feature flag, " "running e2fsck is recommended", EXT3_DYNAMIC_REV); @@ -346,7 +348,7 @@ fail: static int ext3_blkdev_put(struct block_device *bdev) { bd_release(bdev); - return blkdev_put(bdev); + return blkdev_put(bdev, FMODE_READ|FMODE_WRITE); } static int ext3_blkdev_remove(struct ext3_sb_info *sbi) @@ -389,10 +391,14 @@ static void ext3_put_super (struct super_block * sb) { struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; - int i; + int i, err; ext3_xattr_put_super(sb); - journal_destroy(sbi->s_journal); + err = journal_destroy(sbi->s_journal); + sbi->s_journal = NULL; + if (err < 0) + ext3_abort(sb, __func__, "Couldn't clean up the journal"); + if (!(sb->s_flags & MS_RDONLY)) { EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); es->s_state = cpu_to_le16(sbi->s_mount_state); @@ -433,6 +439,7 @@ static void ext3_put_super (struct super_block * sb) ext3_blkdev_remove(sbi); } sb->s_fs_info = NULL; + kfree(sbi->s_blockgroup_lock); kfree(sbi); return; } @@ -471,7 +478,7 @@ static void ext3_destroy_inode(struct inode *inode) kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(void *foo) { struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; @@ -489,7 +496,7 @@ static int init_inodecache(void) sizeof(struct ext3_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (ext3_inode_cachep == NULL) return -ENOMEM; return 0; @@ -544,9 +551,78 @@ static inline void ext3_show_quota_options(struct seq_file *seq, struct super_bl #endif } +/* + * Show an option if + * - it's set to a non-default value OR + * - if the per-sb default is different from the global default + */ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct super_block *sb = vfs->mnt_sb; + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + unsigned long def_mount_opts; + + def_mount_opts = le32_to_cpu(es->s_default_mount_opts); + + if (sbi->s_sb_block != 1) + seq_printf(seq, ",sb=%lu", sbi->s_sb_block); + if (test_opt(sb, MINIX_DF)) + seq_puts(seq, ",minixdf"); + if (test_opt(sb, GRPID)) + seq_puts(seq, ",grpid"); + if (!test_opt(sb, GRPID) && (def_mount_opts & EXT3_DEFM_BSDGROUPS)) + seq_puts(seq, ",nogrpid"); + if (sbi->s_resuid != EXT3_DEF_RESUID || + le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) { + seq_printf(seq, ",resuid=%u", sbi->s_resuid); + } + if (sbi->s_resgid != EXT3_DEF_RESGID || + le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { + seq_printf(seq, ",resgid=%u", sbi->s_resgid); + } + if (test_opt(sb, ERRORS_RO)) { + int def_errors = le16_to_cpu(es->s_errors); + + if (def_errors == EXT3_ERRORS_PANIC || + def_errors == EXT3_ERRORS_CONTINUE) { + seq_puts(seq, ",errors=remount-ro"); + } + } + if (test_opt(sb, ERRORS_CONT)) + seq_puts(seq, ",errors=continue"); + if (test_opt(sb, ERRORS_PANIC)) + seq_puts(seq, ",errors=panic"); + if (test_opt(sb, NO_UID32)) + seq_puts(seq, ",nouid32"); + if (test_opt(sb, DEBUG)) + seq_puts(seq, ",debug"); + if (test_opt(sb, OLDALLOC)) + seq_puts(seq, ",oldalloc"); +#ifdef CONFIG_EXT3_FS_XATTR + if (test_opt(sb, XATTR_USER)) + seq_puts(seq, ",user_xattr"); + if (!test_opt(sb, XATTR_USER) && + (def_mount_opts & EXT3_DEFM_XATTR_USER)) { + seq_puts(seq, ",nouser_xattr"); + } +#endif +#ifdef CONFIG_EXT3_FS_POSIX_ACL + if (test_opt(sb, POSIX_ACL)) + seq_puts(seq, ",acl"); + if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT3_DEFM_ACL)) + seq_puts(seq, ",noacl"); +#endif + if (!test_opt(sb, RESERVATION)) + seq_puts(seq, ",noreservation"); + if (sbi->s_commit_interval) { + seq_printf(seq, ",commit=%u", + (unsigned) (sbi->s_commit_interval / HZ)); + } + if (test_opt(sb, BARRIER)) + seq_puts(seq, ",barrier=1"); + if (test_opt(sb, NOBH)) + seq_puts(seq, ",nobh"); if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) seq_puts(seq, ",data=journal"); @@ -555,19 +631,19 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) seq_puts(seq, ",data=writeback"); + if (test_opt(sb, DATA_ERR_ABORT)) + seq_puts(seq, ",data_err=abort"); + ext3_show_quota_options(seq, sb); return 0; } -static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp) +static struct inode *ext3_nfs_get_inode(struct super_block *sb, + u64 ino, u32 generation) { - __u32 *objp = vobjp; - unsigned long ino = objp[0]; - __u32 generation = objp[1]; struct inode *inode; - struct dentry *result; if (ino < EXT3_FIRST_INO(sb) && ino != EXT3_ROOT_INO) return ERR_PTR(-ESTALE); @@ -582,23 +658,49 @@ static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp) * Currently we don't know the generation for parent directory, so * a generation of 0 means "accept any" */ - inode = iget(sb, ino); - if (inode == NULL) - return ERR_PTR(-ENOMEM); - if (is_bad_inode(inode) || - (generation && inode->i_generation != generation)) { + inode = ext3_iget(sb, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + if (generation && inode->i_generation != generation) { iput(inode); return ERR_PTR(-ESTALE); } - /* now to find a dentry. - * If possible, get a well-connected one - */ - result = d_alloc_anon(inode); - if (!result) { - iput(inode); - return ERR_PTR(-ENOMEM); - } - return result; + + return inode; +} + +static struct dentry *ext3_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, + ext3_nfs_get_inode); +} + +static struct dentry *ext3_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_parent(sb, fid, fh_len, fh_type, + ext3_nfs_get_inode); +} + +/* + * Try to release metadata pages (indirect blocks, directories) which are + * mapped via the block device. Since these pages could have journal heads + * which would prevent try_to_free_buffers() from freeing them, we must use + * jbd layer's try_to_free_buffers() function to release them. + */ +static int bdev_try_to_free_page(struct super_block *sb, struct page *page, + gfp_t wait) +{ + journal_t *journal = EXT3_SB(sb)->s_journal; + + WARN_ON(PageChecked(page)); + if (!page_has_buffers(page)) + return 0; + if (journal) + return journal_try_to_free_buffers(journal, page, + wait & ~__GFP_WAIT); + return try_to_free_buffers(page); } #ifdef CONFIG_QUOTA @@ -612,7 +714,8 @@ static int ext3_acquire_dquot(struct dquot *dquot); static int ext3_release_dquot(struct dquot *dquot); static int ext3_mark_dquot_dirty(struct dquot *dquot); static int ext3_write_info(struct super_block *sb, int type); -static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path); +static int ext3_quota_on(struct super_block *sb, int type, int format_id, + char *path, int remount); static int ext3_quota_on_mount(struct super_block *sb, int type); static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off); @@ -631,7 +734,9 @@ static struct dquot_operations ext3_quota_operations = { .acquire_dquot = ext3_acquire_dquot, .release_dquot = ext3_release_dquot, .mark_dirty = ext3_mark_dquot_dirty, - .write_info = ext3_write_info + .write_info = ext3_write_info, + .alloc_dquot = dquot_alloc, + .destroy_dquot = dquot_destroy, }; static struct quotactl_ops ext3_qctl_operations = { @@ -648,15 +753,14 @@ static struct quotactl_ops ext3_qctl_operations = { static const struct super_operations ext3_sops = { .alloc_inode = ext3_alloc_inode, .destroy_inode = ext3_destroy_inode, - .read_inode = ext3_read_inode, .write_inode = ext3_write_inode, .dirty_inode = ext3_dirty_inode, .delete_inode = ext3_delete_inode, .put_super = ext3_put_super, .write_super = ext3_write_super, .sync_fs = ext3_sync_fs, - .write_super_lockfs = ext3_write_super_lockfs, - .unlockfs = ext3_unlockfs, + .freeze_fs = ext3_freeze, + .unfreeze_fs = ext3_unfreeze, .statfs = ext3_statfs, .remount_fs = ext3_remount, .clear_inode = ext3_clear_inode, @@ -665,11 +769,13 @@ static const struct super_operations ext3_sops = { .quota_read = ext3_quota_read, .quota_write = ext3_quota_write, #endif + .bdev_try_to_free_page = bdev_try_to_free_page, }; -static struct export_operations ext3_export_ops = { +static const struct export_operations ext3_export_ops = { + .fh_to_dentry = ext3_fh_to_dentry, + .fh_to_parent = ext3_fh_to_parent, .get_parent = ext3_get_parent, - .get_dentry = ext3_get_dentry, }; enum { @@ -680,13 +786,14 @@ enum { Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh, Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev, Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, + Opt_data_err_abort, Opt_data_err_ignore, Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, Opt_grpquota }; -static match_table_t tokens = { +static const match_table_t tokens = { {Opt_bsd_df, "bsddf"}, {Opt_minix_df, "minixdf"}, {Opt_grpid, "grpid"}, @@ -722,6 +829,8 @@ static match_table_t tokens = { {Opt_data_journal, "data=journal"}, {Opt_data_ordered, "data=ordered"}, {Opt_data_writeback, "data=writeback"}, + {Opt_data_err_abort, "data_err=abort"}, + {Opt_data_err_ignore, "data_err=ignore"}, {Opt_offusrjquota, "usrjquota="}, {Opt_usrjquota, "usrjquota=%s"}, {Opt_offgrpjquota, "grpjquota="}, @@ -733,8 +842,8 @@ static match_table_t tokens = { {Opt_quota, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_barrier, "barrier=%u"}, - {Opt_err, NULL}, {Opt_resize, "resize"}, + {Opt_err, NULL}, }; static ext3_fsblk_t get_sb_block(void **data) @@ -768,7 +877,7 @@ static int parse_options (char *options, struct super_block *sb, int data_opt = 0; int option; #ifdef CONFIG_QUOTA - int qtype; + int qtype, qfmt; char *qname; #endif @@ -937,6 +1046,12 @@ static int parse_options (char *options, struct super_block *sb, sbi->s_mount_opt |= data_opt; } break; + case Opt_data_err_abort: + set_opt(sbi->s_mount_opt, DATA_ERR_ABORT); + break; + case Opt_data_err_ignore: + clear_opt(sbi->s_mount_opt, DATA_ERR_ABORT); + break; #ifdef CONFIG_QUOTA case Opt_usrjquota: qtype = USRQUOTA; @@ -944,9 +1059,10 @@ static int parse_options (char *options, struct super_block *sb, case Opt_grpjquota: qtype = GRPQUOTA; set_qf_name: - if (sb_any_quota_enabled(sb)) { + if (sb_any_quota_loaded(sb) && + !sbi->s_qf_names[qtype]) { printk(KERN_ERR - "EXT3-fs: Cannot change journalled " + "EXT3-fs: Cannot change journaled " "quota options when quota turned on.\n"); return 0; } @@ -982,9 +1098,10 @@ set_qf_name: case Opt_offgrpjquota: qtype = GRPQUOTA; clear_qf_name: - if (sb_any_quota_enabled(sb)) { + if (sb_any_quota_loaded(sb) && + sbi->s_qf_names[qtype]) { printk(KERN_ERR "EXT3-fs: Cannot change " - "journalled quota options when " + "journaled quota options when " "quota turned on.\n"); return 0; } @@ -995,10 +1112,19 @@ clear_qf_name: sbi->s_qf_names[qtype] = NULL; break; case Opt_jqfmt_vfsold: - sbi->s_jquota_fmt = QFMT_VFS_OLD; - break; + qfmt = QFMT_VFS_OLD; + goto set_qf_format; case Opt_jqfmt_vfsv0: - sbi->s_jquota_fmt = QFMT_VFS_V0; + qfmt = QFMT_VFS_V0; +set_qf_format: + if (sb_any_quota_loaded(sb) && + sbi->s_jquota_fmt != qfmt) { + printk(KERN_ERR "EXT3-fs: Cannot change " + "journaled quota options when " + "quota turned on.\n"); + return 0; + } + sbi->s_jquota_fmt = qfmt; break; case Opt_quota: case Opt_usrquota: @@ -1010,7 +1136,7 @@ clear_qf_name: set_opt(sbi->s_mount_opt, GRPQUOTA); break; case Opt_noquota: - if (sb_any_quota_enabled(sb)) { + if (sb_any_quota_loaded(sb)) { printk(KERN_ERR "EXT3-fs: Cannot change quota " "options when quota turned on.\n"); return 0; @@ -1023,6 +1149,9 @@ clear_qf_name: case Opt_quota: case Opt_usrquota: case Opt_grpquota: + printk(KERN_ERR + "EXT3-fs: quota options not supported.\n"); + break; case Opt_usrjquota: case Opt_grpjquota: case Opt_offusrjquota: @@ -1030,7 +1159,7 @@ clear_qf_name: case Opt_jqfmt_vfsold: case Opt_jqfmt_vfsv0: printk(KERN_ERR - "EXT3-fs: journalled quota options not " + "EXT3-fs: journaled quota options not " "supported.\n"); break; case Opt_noquota: @@ -1092,14 +1221,14 @@ clear_qf_name: } if (!sbi->s_jquota_fmt) { - printk(KERN_ERR "EXT3-fs: journalled quota format " + printk(KERN_ERR "EXT3-fs: journaled quota format " "not specified.\n"); return 0; } } else { if (sbi->s_jquota_fmt) { - printk(KERN_ERR "EXT3-fs: journalled quota format " - "specified with no journalling " + printk(KERN_ERR "EXT3-fs: journaled quota format " + "specified with no journaling " "enabled.\n"); return 0; } @@ -1145,11 +1274,11 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, inconsistencies, to force a fsck at reboot. But for a plain journaled filesystem we can keep it set as valid forever! :) */ - es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT3_VALID_FS); + es->s_state &= cpu_to_le16(~EXT3_VALID_FS); #endif if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT); - es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); + le16_add_cpu(&es->s_mnt_count, 1); es->s_mtime = cpu_to_le32(get_seconds()); ext3_update_dynamic_rev(sb); EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); @@ -1177,28 +1306,24 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, } /* Called at mount-time, super-block is locked */ -static int ext3_check_descriptors (struct super_block * sb) +static int ext3_check_descriptors(struct super_block *sb) { struct ext3_sb_info *sbi = EXT3_SB(sb); - ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); - ext3_fsblk_t last_block; - struct ext3_group_desc * gdp = NULL; - int desc_block = 0; int i; ext3_debug ("Checking group descriptors"); - for (i = 0; i < sbi->s_groups_count; i++) - { + for (i = 0; i < sbi->s_groups_count; i++) { + struct ext3_group_desc *gdp = ext3_get_group_desc(sb, i, NULL); + ext3_fsblk_t first_block = ext3_group_first_block_no(sb, i); + ext3_fsblk_t last_block; + if (i == sbi->s_groups_count - 1) last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; else last_block = first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); - if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) - gdp = (struct ext3_group_desc *) - sbi->s_group_desc[desc_block++]->b_data; if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) { @@ -1220,7 +1345,7 @@ static int ext3_check_descriptors (struct super_block * sb) return 0; } if (le32_to_cpu(gdp->bg_inode_table) < first_block || - le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > + le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group - 1 > last_block) { ext3_error (sb, "ext3_check_descriptors", @@ -1230,8 +1355,6 @@ static int ext3_check_descriptors (struct super_block * sb) le32_to_cpu(gdp->bg_inode_table)); return 0; } - first_block += EXT3_BLOCKS_PER_GROUP(sb); - gdp++; } sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb)); @@ -1299,7 +1422,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, int ret = ext3_quota_on_mount(sb, i); if (ret < 0) printk(KERN_ERR - "EXT3-fs: Cannot turn on journalled " + "EXT3-fs: Cannot turn on journaled " "quota: error %d\n", ret); } } @@ -1308,8 +1431,8 @@ static void ext3_orphan_cleanup (struct super_block * sb, while (es->s_last_orphan) { struct inode *inode; - if (!(inode = - ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) { + inode = ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)); + if (IS_ERR(inode)) { es->s_last_orphan = 0; break; } @@ -1319,7 +1442,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, if (inode->i_nlink) { printk(KERN_DEBUG "%s: truncating inode %lu to %Ld bytes\n", - __FUNCTION__, inode->i_ino, inode->i_size); + __func__, inode->i_ino, inode->i_size); jbd_debug(2, "truncating inode %lu to %Ld bytes\n", inode->i_ino, inode->i_size); ext3_truncate(inode); @@ -1327,7 +1450,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, } else { printk(KERN_DEBUG "%s: deleting unreferenced inode %lu\n", - __FUNCTION__, inode->i_ino); + __func__, inode->i_ino); jbd_debug(2, "deleting unreferenced inode %lu\n", inode->i_ino); nr_orphans++; @@ -1347,7 +1470,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, /* Turn quotas off */ for (i = 0; i < MAXQUOTAS; i++) { if (sb_dqopt(sb)->files[i]) - vfs_quota_off(sb, i); + vfs_quota_off(sb, i, 0); } #endif sb->s_flags = s_flags; /* Restore MS_RDONLY status */ @@ -1361,11 +1484,31 @@ static void ext3_orphan_cleanup (struct super_block * sb, static loff_t ext3_max_size(int bits) { loff_t res = EXT3_NDIR_BLOCKS; - /* This constant is calculated to be the largest file size for a - * dense, 4k-blocksize file such that the total number of + int meta_blocks; + loff_t upper_limit; + + /* This is calculated to be the largest file size for a + * dense, file such that the total number of * sectors in the file, including data and all indirect blocks, - * does not exceed 2^32. */ - const loff_t upper_limit = 0x1ff7fffd000LL; + * does not exceed 2^32 -1 + * __u32 i_blocks representing the total number of + * 512 bytes blocks of the file + */ + upper_limit = (1LL << 32) - 1; + + /* total blocks in file system block size */ + upper_limit >>= (bits - 9); + + + /* indirect blocks */ + meta_blocks = 1; + /* double indirect blocks */ + meta_blocks += 1 + (1LL << (bits-2)); + /* tripple indirect blocks */ + meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2))); + + upper_limit -= meta_blocks; + upper_limit <<= bits; res += 1LL << (bits-2); res += 1LL << (2*(bits-2)); @@ -1373,6 +1516,10 @@ static loff_t ext3_max_size(int bits) res <<= bits; if (res > upper_limit) res = upper_limit; + + if (res > MAX_LFS_FILESIZE) + res = MAX_LFS_FILESIZE; + return res; } @@ -1414,15 +1561,25 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) int db_count; int i; int needs_recovery; + int ret = -EINVAL; __le32 features; + int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) return -ENOMEM; + + sbi->s_blockgroup_lock = + kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); + if (!sbi->s_blockgroup_lock) { + kfree(sbi); + return -ENOMEM; + } sb->s_fs_info = sbi; sbi->s_mount_opt = 0; sbi->s_resuid = EXT3_DEF_RESUID; sbi->s_resgid = EXT3_DEF_RESGID; + sbi->s_sb_block = sb_block; unlock_kernel(); @@ -1482,10 +1639,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC) set_opt(sbi->s_mount_opt, ERRORS_PANIC); - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO) - set_opt(sbi->s_mount_opt, ERRORS_RO); - else + else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_CONTINUE) set_opt(sbi->s_mount_opt, ERRORS_CONT); + else + set_opt(sbi->s_mount_opt, ERRORS_RO); sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); @@ -1548,7 +1705,11 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) } brelse (bh); - sb_set_blocksize(sb, blocksize); + if (!sb_set_blocksize(sb, blocksize)) { + printk(KERN_ERR "EXT3-fs: bad blocksize %d.\n", + blocksize); + goto out_fail; + } logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; bh = sb_bread(sb, logic_sb_block); @@ -1595,7 +1756,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); - if (EXT3_INODE_SIZE(sb) == 0) + if (EXT3_INODE_SIZE(sb) == 0 || EXT3_INODES_PER_GROUP(sb) == 0) goto cantfind_ext3; sbi->s_inodes_per_block = blocksize / EXT3_INODE_SIZE(sb); if (sbi->s_inodes_per_block == 0) @@ -1610,6 +1771,18 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) for (i=0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; + i = le32_to_cpu(es->s_flags); + if (i & EXT2_FLAGS_UNSIGNED_HASH) + sbi->s_hash_unsigned = 3; + else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { +#ifdef __CHAR_UNSIGNED__ + es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); + sbi->s_hash_unsigned = 3; +#else + es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); +#endif + sb->s_dirt = 1; + } if (sbi->s_blocks_per_group > blocksize * 8) { printk (KERN_ERR @@ -1654,7 +1827,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) goto failed_mount; } - bgl_lock_init(&sbi->s_blockgroup_lock); + bgl_lock_init(sbi->s_blockgroup_lock); for (i = 0; i < db_count; i++) { block = descriptor_loc(sb, logic_sb_block, i); @@ -1674,12 +1847,20 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); - percpu_counter_init(&sbi->s_freeblocks_counter, - ext3_count_free_blocks(sb)); - percpu_counter_init(&sbi->s_freeinodes_counter, - ext3_count_free_inodes(sb)); - percpu_counter_init(&sbi->s_dirs_counter, - ext3_count_dirs(sb)); + err = percpu_counter_init(&sbi->s_freeblocks_counter, + ext3_count_free_blocks(sb)); + if (!err) { + err = percpu_counter_init(&sbi->s_freeinodes_counter, + ext3_count_free_inodes(sb)); + } + if (!err) { + err = percpu_counter_init(&sbi->s_dirs_counter, + ext3_count_dirs(sb)); + } + if (err) { + printk(KERN_ERR "EXT3-fs: insufficient memory\n"); + goto failed_mount3; + } /* per fileystem reservation list head & lock */ spin_lock_init(&sbi->s_rsv_window_lock); @@ -1769,19 +1950,24 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) * so we can safely mount the rest of the filesystem now. */ - root = iget(sb, EXT3_ROOT_INO); - sb->s_root = d_alloc_root(root); - if (!sb->s_root) { + root = ext3_iget(sb, EXT3_ROOT_INO); + if (IS_ERR(root)) { printk(KERN_ERR "EXT3-fs: get root inode failed\n"); - iput(root); + ret = PTR_ERR(root); goto failed_mount4; } if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { - dput(sb->s_root); - sb->s_root = NULL; + iput(root); printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n"); goto failed_mount4; } + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + printk(KERN_ERR "EXT3-fs: get root dentry failed\n"); + iput(root); + ret = -ENOMEM; + goto failed_mount4; + } ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY); /* @@ -1833,7 +2019,7 @@ out_fail: sb->s_fs_info = NULL; kfree(sbi); lock_kernel(); - return -EINVAL; + return ret; } /* @@ -1856,6 +2042,10 @@ static void ext3_init_journal_params(struct super_block *sb, journal_t *journal) journal->j_flags |= JFS_BARRIER; else journal->j_flags &= ~JFS_BARRIER; + if (test_opt(sb, DATA_ERR_ABORT)) + journal->j_flags |= JFS_ABORT_ON_SYNCDATA_ERR; + else + journal->j_flags &= ~JFS_ABORT_ON_SYNCDATA_ERR; spin_unlock(&journal->j_state_lock); } @@ -1869,8 +2059,8 @@ static journal_t *ext3_get_journal(struct super_block *sb, * things happen if we iget() an unused inode, as the subsequent * iput() will try to delete it. */ - journal_inode = iget(sb, journal_inum); - if (!journal_inode) { + journal_inode = ext3_iget(sb, journal_inum); + if (IS_ERR(journal_inode)) { printk(KERN_ERR "EXT3-fs: no journal found.\n"); return NULL; } @@ -1883,7 +2073,7 @@ static journal_t *ext3_get_journal(struct super_block *sb, jbd_debug(2, "Journal inode found at %p: %Ld bytes\n", journal_inode, journal_inode->i_size); - if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) { + if (!S_ISREG(journal_inode->i_mode)) { printk(KERN_ERR "EXT3-fs: invalid journal inode.\n"); iput(journal_inode); return NULL; @@ -1920,7 +2110,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb, if (bd_claim(bdev, sb)) { printk(KERN_ERR "EXT3: failed to claim external journal device.\n"); - blkdev_put(bdev); + blkdev_put(bdev, FMODE_READ|FMODE_WRITE); return NULL; } @@ -2084,6 +2274,7 @@ static int ext3_create_journal(struct super_block * sb, unsigned int journal_inum) { journal_t *journal; + int err; if (sb->s_flags & MS_RDONLY) { printk(KERN_ERR "EXT3-fs: readonly filesystem when trying to " @@ -2091,13 +2282,15 @@ static int ext3_create_journal(struct super_block * sb, return -EROFS; } - if (!(journal = ext3_get_journal(sb, journal_inum))) + journal = ext3_get_journal(sb, journal_inum); + if (!journal) return -EINVAL; printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n", journal_inum); - if (journal_create(journal)) { + err = journal_create(journal); + if (err) { printk(KERN_ERR "EXT3-fs: error creating journal.\n"); journal_destroy(journal); return -EIO; @@ -2118,21 +2311,23 @@ static int ext3_create_journal(struct super_block * sb, return 0; } -static void ext3_commit_super (struct super_block * sb, - struct ext3_super_block * es, +static int ext3_commit_super(struct super_block *sb, + struct ext3_super_block *es, int sync) { struct buffer_head *sbh = EXT3_SB(sb)->s_sbh; + int error = 0; if (!sbh) - return; + return error; es->s_wtime = cpu_to_le32(get_seconds()); es->s_free_blocks_count = cpu_to_le32(ext3_count_free_blocks(sb)); es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); BUFFER_TRACE(sbh, "marking dirty"); mark_buffer_dirty(sbh); if (sync) - sync_dirty_buffer(sbh); + error = sync_dirty_buffer(sbh); + return error; } @@ -2147,7 +2342,9 @@ static void ext3_mark_recovery_complete(struct super_block * sb, journal_t *journal = EXT3_SB(sb)->s_journal; journal_lock_updates(journal); - journal_flush(journal); + if (journal_flush(journal) < 0) + goto out; + lock_super(sb); if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && sb->s_flags & MS_RDONLY) { @@ -2156,6 +2353,8 @@ static void ext3_mark_recovery_complete(struct super_block * sb, ext3_commit_super(sb, es, 1); } unlock_super(sb); + +out: journal_unlock_updates(journal); } @@ -2183,9 +2382,9 @@ static void ext3_clear_journal_err(struct super_block * sb, char nbuf[16]; errstr = ext3_decode_error(sb, j_errno, nbuf); - ext3_warning(sb, __FUNCTION__, "Filesystem error recorded " + ext3_warning(sb, __func__, "Filesystem error recorded " "from previous mount: %s", errstr); - ext3_warning(sb, __FUNCTION__, "Marking fs in need of " + ext3_warning(sb, __func__, "Marking fs in need of " "filesystem check."); EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; @@ -2217,12 +2416,9 @@ int ext3_force_commit(struct super_block *sb) /* * Ext3 always journals updates to the superblock itself, so we don't * have to propagate any other updates to the superblock on disk at this - * point. Just start an async writeback to get the buffers on their way - * to the disk. - * - * This implicitly triggers the writebehind on sync(). + * point. (We can probably nuke this function altogether, and remove + * any mention to sb->s_dirt in all of fs/ext3; eventual cleanup...) */ - static void ext3_write_super (struct super_block * sb) { if (mutex_trylock(&sb->s_lock) != 0) @@ -2246,28 +2442,44 @@ static int ext3_sync_fs(struct super_block *sb, int wait) * LVM calls this function before a (read-only) snapshot is created. This * gives us a chance to flush the journal completely and mark the fs clean. */ -static void ext3_write_super_lockfs(struct super_block *sb) +static int ext3_freeze(struct super_block *sb) { + int error = 0; + journal_t *journal; sb->s_dirt = 0; if (!(sb->s_flags & MS_RDONLY)) { - journal_t *journal = EXT3_SB(sb)->s_journal; + journal = EXT3_SB(sb)->s_journal; /* Now we set up the journal barrier. */ journal_lock_updates(journal); - journal_flush(journal); + + /* + * We don't want to clear needs_recovery flag when we failed + * to flush the journal. + */ + error = journal_flush(journal); + if (error < 0) + goto out; /* Journal blocked and flushed, clear needs_recovery flag. */ EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); + error = ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); + if (error) + goto out; } + return 0; + +out: + journal_unlock_updates(journal); + return error; } /* * Called by LVM after the snapshot is done. We need to reset the RECOVER * flag here, even though the filesystem is not technically dirty yet. */ -static void ext3_unlockfs(struct super_block *sb) +static int ext3_unfreeze(struct super_block *sb) { if (!(sb->s_flags & MS_RDONLY)) { lock_super(sb); @@ -2277,6 +2489,7 @@ static void ext3_unlockfs(struct super_block *sb) unlock_super(sb); journal_unlock_updates(EXT3_SB(sb)->s_journal); } + return 0; } static int ext3_remount (struct super_block * sb, int * flags, char * data) @@ -2312,7 +2525,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) } if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) - ext3_abort(sb, __FUNCTION__, "Abort forced by user"); + ext3_abort(sb, __func__, "Abort forced by user"); sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); @@ -2423,19 +2636,19 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) struct super_block *sb = dentry->d_sb; struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; - ext3_fsblk_t overhead; - int i; u64 fsid; - if (test_opt (sb, MINIX_DF)) - overhead = 0; - else { - unsigned long ngroups; - ngroups = EXT3_SB(sb)->s_groups_count; + if (test_opt(sb, MINIX_DF)) { + sbi->s_overhead_last = 0; + } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { + unsigned long ngroups = sbi->s_groups_count, i; + ext3_fsblk_t overhead = 0; smp_rmb(); /* - * Compute the overhead (FS structures) + * Compute the overhead (FS structures). This is constant + * for a given filesystem unless the number of block groups + * changes so we cache the previous value until it does. */ /* @@ -2459,18 +2672,23 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) * Every block group has an inode bitmap, a block * bitmap, and an inode table. */ - overhead += (ngroups * (2 + EXT3_SB(sb)->s_itb_per_group)); + overhead += ngroups * (2 + sbi->s_itb_per_group); + sbi->s_overhead_last = overhead; + smp_wmb(); + sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count); } buf->f_type = EXT3_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; - buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead; - buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); + buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last; + buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); + es->s_free_blocks_count = cpu_to_le32(buf->f_bfree); buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) buf->f_bavail = 0; buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); + buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); + es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); buf->f_namelen = EXT3_NAME_LEN; fsid = le64_to_cpup((void *)es->s_uuid) ^ le64_to_cpup((void *)es->s_uuid + sizeof(u64)); @@ -2519,8 +2737,14 @@ static int ext3_dquot_drop(struct inode *inode) /* We may delete quota structure so we need to reserve enough blocks */ handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { + /* + * We call dquot_drop() anyway to at least release references + * to quota structures so that umount does not hang. + */ + dquot_drop(inode); return PTR_ERR(handle); + } ret = dquot_drop(inode); err = ext3_journal_stop(handle); if (!ret) @@ -2569,8 +2793,11 @@ static int ext3_release_dquot(struct dquot *dquot) handle = ext3_journal_start(dquot_to_inode(dquot), EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { + /* Release dquot anyway to avoid endless cycle in dqput() */ + dquot_release(dquot); return PTR_ERR(handle); + } ret = dquot_release(dquot); err = ext3_journal_stop(handle); if (!ret) @@ -2580,7 +2807,7 @@ static int ext3_release_dquot(struct dquot *dquot) static int ext3_mark_dquot_dirty(struct dquot *dquot) { - /* Are we journalling quotas? */ + /* Are we journaling quotas? */ if (EXT3_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || EXT3_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { dquot_mark_dquot_dirty(dquot); @@ -2620,32 +2847,56 @@ static int ext3_quota_on_mount(struct super_block *sb, int type) * Standard function to be called on quota_on */ static int ext3_quota_on(struct super_block *sb, int type, int format_id, - char *path) + char *name, int remount) { int err; - struct nameidata nd; + struct path path; if (!test_opt(sb, QUOTA)) return -EINVAL; - /* Not journalling quota? */ - if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] && - !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) - return vfs_quota_on(sb, type, format_id, path); - err = path_lookup(path, LOOKUP_FOLLOW, &nd); + /* When remounting, no checks are needed and in fact, name is NULL */ + if (remount) + return vfs_quota_on(sb, type, format_id, name, remount); + + err = kern_path(name, LOOKUP_FOLLOW, &path); if (err) return err; + /* Quotafile not on the same filesystem? */ - if (nd.mnt->mnt_sb != sb) { - path_release(&nd); + if (path.mnt->mnt_sb != sb) { + path_put(&path); return -EXDEV; } - /* Quotafile not of fs root? */ - if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode) - printk(KERN_WARNING - "EXT3-fs: Quota file not on filesystem root. " - "Journalled quota will not work.\n"); - path_release(&nd); - return vfs_quota_on(sb, type, format_id, path); + /* Journaling quota? */ + if (EXT3_SB(sb)->s_qf_names[type]) { + /* Quotafile not of fs root? */ + if (path.dentry->d_parent != sb->s_root) + printk(KERN_WARNING + "EXT3-fs: Quota file not on filesystem root. " + "Journaled quota will not work.\n"); + } + + /* + * When we journal data on quota file, we have to flush journal to see + * all updates to the file when we bypass pagecache... + */ + if (ext3_should_journal_data(path.dentry->d_inode)) { + /* + * We don't need to lock updates but journal_flush() could + * otherwise be livelocked... + */ + journal_lock_updates(EXT3_SB(sb)->s_journal); + err = journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + if (err) { + path_put(&path); + return err; + } + } + + err = vfs_quota_on_path(sb, type, format_id, &path); + path_put(&path); + return err; } /* Read data from quotafile - avoid pagecache and such because we cannot afford @@ -2703,6 +2954,12 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, struct buffer_head *bh; handle_t *handle = journal_current_handle(); + if (!handle) { + printk(KERN_WARNING "EXT3-fs: Quota write (off=%Lu, len=%Lu)" + " cancelled because transaction is not started.\n", + (unsigned long long)off, (unsigned long long)len); + return -EIO; + } mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? @@ -2737,8 +2994,10 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, blk++; } out: - if (len == towrite) + if (len == towrite) { + mutex_unlock(&inode->i_mutex); return err; + } if (inode->i_size < off+len-towrite) { i_size_write(inode, off+len-towrite); EXT3_I(inode)->i_disksize = inode->i_size;