diff options
Diffstat (limited to 'fs/ext3/super.c')
| -rw-r--r-- | fs/ext3/super.c | 392 | 
1 files changed, 242 insertions, 150 deletions
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 2fedaf8b501..08cdfe5461e 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -17,29 +17,23 @@   */  #include <linux/module.h> -#include <linux/string.h> -#include <linux/fs.h> -#include <linux/time.h> -#include <linux/jbd.h> -#include <linux/ext3_fs.h> -#include <linux/ext3_jbd.h> -#include <linux/slab.h> -#include <linux/init.h>  #include <linux/blkdev.h>  #include <linux/parser.h> -#include <linux/smp_lock.h> -#include <linux/buffer_head.h>  #include <linux/exportfs.h> -#include <linux/vfs.h> +#include <linux/statfs.h>  #include <linux/random.h>  #include <linux/mount.h> -#include <linux/namei.h>  #include <linux/quotaops.h>  #include <linux/seq_file.h>  #include <linux/log2.h> +#include <linux/cleancache.h> +#include <linux/namei.h>  #include <asm/uaccess.h> +#define CREATE_TRACE_POINTS + +#include "ext3.h"  #include "xattr.h"  #include "acl.h"  #include "namei.h" @@ -71,11 +65,6 @@ static int ext3_freeze(struct super_block *sb);  /*   * Wrappers for journal_start/end. - * - * The only special thing we need to do here is to make sure that all - * journal_end calls result in the superblock being marked dirty, so - * that sync() will call the filesystem's write_super callback if - * appropriate.   */  handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)  { @@ -97,12 +86,6 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)  	return journal_start(journal, nblocks);  } -/* - * The only special thing we need to do here is to make sure that all - * journal_stop calls result in the superblock being marked dirty, so - * that sync() will call the filesystem's write_super callback if - * appropriate. - */  int __ext3_journal_stop(const char *where, handle_t *handle)  {  	struct super_block *sb; @@ -144,12 +127,16 @@ void ext3_journal_abort_handle(const char *caller, const char *err_fn,  void ext3_msg(struct super_block *sb, const char *prefix,  		const char *fmt, ...)  { +	struct va_format vaf;  	va_list args;  	va_start(args, fmt); -	printk("%sEXT3-fs (%s): ", prefix, sb->s_id); -	vprintk(fmt, args); -	printk("\n"); + +	vaf.fmt = fmt; +	vaf.va = &args; + +	printk("%sEXT3-fs (%s): %pV\n", prefix, sb->s_id, &vaf); +  	va_end(args);  } @@ -188,6 +175,11 @@ static void ext3_handle_error(struct super_block *sb)  	if (test_opt (sb, ERRORS_RO)) {  		ext3_msg(sb, KERN_CRIT,  			"error: remounting filesystem read-only"); +		/* +		 * Make sure updated value of ->s_mount_state will be visible +		 * before ->s_flags update. +		 */ +		smp_wmb();  		sb->s_flags |= MS_RDONLY;  	}  	ext3_commit_super(sb, es, 1); @@ -196,15 +188,20 @@ static void ext3_handle_error(struct super_block *sb)  			sb->s_id);  } -void ext3_error (struct super_block * sb, const char * function, -		 const char * fmt, ...) +void ext3_error(struct super_block *sb, const char *function, +		const char *fmt, ...)  { +	struct va_format vaf;  	va_list args;  	va_start(args, fmt); -	printk(KERN_CRIT "EXT3-fs error (device %s): %s: ",sb->s_id, function); -	vprintk(fmt, args); -	printk("\n"); + +	vaf.fmt = fmt; +	vaf.va = &args; + +	printk(KERN_CRIT "EXT3-fs error (device %s): %s: %pV\n", +	       sb->s_id, function, &vaf); +  	va_end(args);  	ext3_handle_error(sb); @@ -275,15 +272,20 @@ void __ext3_std_error (struct super_block * sb, const char * function,   * case we take the easy way out and panic immediately.   */ -void ext3_abort (struct super_block * sb, const char * function, -		 const char * fmt, ...) +void ext3_abort(struct super_block *sb, const char *function, +		 const char *fmt, ...)  { +	struct va_format vaf;  	va_list args;  	va_start(args, fmt); -	printk(KERN_CRIT "EXT3-fs (%s): error: %s: ", sb->s_id, function); -	vprintk(fmt, args); -	printk("\n"); + +	vaf.fmt = fmt; +	vaf.va = &args; + +	printk(KERN_CRIT "EXT3-fs (%s): error: %s: %pV\n", +	       sb->s_id, function, &vaf); +  	va_end(args);  	if (test_opt(sb, ERRORS_PANIC)) @@ -295,22 +297,32 @@ void ext3_abort (struct super_block * sb, const char * function,  	ext3_msg(sb, KERN_CRIT,  		"error: remounting filesystem read-only");  	EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; -	sb->s_flags |= MS_RDONLY;  	set_opt(EXT3_SB(sb)->s_mount_opt, ABORT); +	/* +	 * Make sure updated value of ->s_mount_state will be visible +	 * before ->s_flags update. +	 */ +	smp_wmb(); +	sb->s_flags |= MS_RDONLY; +  	if (EXT3_SB(sb)->s_journal)  		journal_abort(EXT3_SB(sb)->s_journal, -EIO);  } -void ext3_warning (struct super_block * sb, const char * function, -		   const char * fmt, ...) +void ext3_warning(struct super_block *sb, const char *function, +		  const char *fmt, ...)  { +	struct va_format vaf;  	va_list args;  	va_start(args, fmt); -	printk(KERN_WARNING "EXT3-fs (%s): warning: %s: ", -	       sb->s_id, function); -	vprintk(fmt, args); -	printk("\n"); + +	vaf.fmt = fmt; +	vaf.va = &args; + +	printk(KERN_WARNING "EXT3-fs (%s): warning: %s: %pV\n", +	       sb->s_id, function, &vaf); +  	va_end(args);  } @@ -347,13 +359,13 @@ static struct block_device *ext3_blkdev_get(dev_t dev, struct super_block *sb)  	struct block_device *bdev;  	char b[BDEVNAME_SIZE]; -	bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); +	bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb);  	if (IS_ERR(bdev))  		goto fail;  	return bdev;  fail: -	ext3_msg(sb, "error: failed to open journal device %s: %ld", +	ext3_msg(sb, KERN_ERR, "error: failed to open journal device %s: %ld",  		__bdevname(dev, b), PTR_ERR(bdev));  	return NULL; @@ -362,23 +374,19 @@ fail:  /*   * Release the journal device   */ -static int ext3_blkdev_put(struct block_device *bdev) +static void ext3_blkdev_put(struct block_device *bdev)  { -	bd_release(bdev); -	return blkdev_put(bdev, FMODE_READ|FMODE_WRITE); +	blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);  } -static int ext3_blkdev_remove(struct ext3_sb_info *sbi) +static void ext3_blkdev_remove(struct ext3_sb_info *sbi)  {  	struct block_device *bdev; -	int ret = -ENODEV; -  	bdev = sbi->journal_bdev;  	if (bdev) { -		ret = ext3_blkdev_put(bdev); +		ext3_blkdev_put(bdev);  		sbi->journal_bdev = NULL;  	} -	return ret;  }  static inline struct inode *orphan_list_entry(struct list_head *l) @@ -480,6 +488,20 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)  	return &ei->vfs_inode;  } +static int ext3_drop_inode(struct inode *inode) +{ +	int drop = generic_drop_inode(inode); + +	trace_ext3_drop_inode(inode, drop); +	return drop; +} + +static void ext3_i_callback(struct rcu_head *head) +{ +	struct inode *inode = container_of(head, struct inode, i_rcu); +	kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); +} +  static void ext3_destroy_inode(struct inode *inode)  {  	if (!list_empty(&(EXT3_I(inode)->i_orphan))) { @@ -490,7 +512,7 @@ static void ext3_destroy_inode(struct inode *inode)  				false);  		dump_stack();  	} -	kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); +	call_rcu(&inode->i_rcu, ext3_i_callback);  }  static void init_once(void *foo) @@ -505,7 +527,7 @@ static void init_once(void *foo)  	inode_init_once(&ei->vfs_inode);  } -static int init_inodecache(void) +static int __init init_inodecache(void)  {  	ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",  					     sizeof(struct ext3_inode_info), @@ -519,6 +541,11 @@ static int init_inodecache(void)  static void destroy_inodecache(void)  { +	/* +	 * Make sure all delayed rcu free inodes are flushed before we +	 * destroy cache. +	 */ +	rcu_barrier();  	kmem_cache_destroy(ext3_inode_cachep);  } @@ -576,9 +603,9 @@ static char *data_mode_string(unsigned long mode)   *  - 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) +static int ext3_show_options(struct seq_file *seq, struct dentry *root)  { -	struct super_block *sb = vfs->mnt_sb; +	struct super_block *sb = root->d_sb;  	struct ext3_sb_info *sbi = EXT3_SB(sb);  	struct ext3_super_block *es = sbi->s_es;  	unsigned long def_mount_opts; @@ -593,13 +620,15 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)  		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 || +	if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT3_DEF_RESUID)) ||  	    le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) { -		seq_printf(seq, ",resuid=%u", sbi->s_resuid); +		seq_printf(seq, ",resuid=%u", +				from_kuid_munged(&init_user_ns, sbi->s_resuid));  	} -	if (sbi->s_resgid != EXT3_DEF_RESGID || +	if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT3_DEF_RESGID)) ||  	    le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { -		seq_printf(seq, ",resgid=%u", sbi->s_resgid); +		seq_printf(seq, ",resgid=%u", +				from_kgid_munged(&init_user_ns, sbi->s_resgid));  	}  	if (test_opt(sb, ERRORS_RO)) {  		int def_errors = le16_to_cpu(es->s_errors); @@ -617,8 +646,6 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)  		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"); @@ -731,7 +758,7 @@ 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); +			 struct path *path);  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); @@ -764,6 +791,7 @@ static const struct super_operations ext3_sops = {  	.destroy_inode	= ext3_destroy_inode,  	.write_inode	= ext3_write_inode,  	.dirty_inode	= ext3_dirty_inode, +	.drop_inode	= ext3_drop_inode,  	.evict_inode	= ext3_evict_inode,  	.put_super	= ext3_put_super,  	.sync_fs	= ext3_sync_fs, @@ -792,6 +820,7 @@ enum {  	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,  	Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,  	Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev, +	Opt_journal_path,  	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, @@ -833,6 +862,7 @@ static const match_table_t tokens = {  	{Opt_journal_update, "journal=update"},  	{Opt_journal_inum, "journal=%u"},  	{Opt_journal_dev, "journal_dev=%u"}, +	{Opt_journal_path, "journal_path=%s"},  	{Opt_abort, "abort"},  	{Opt_data_journal, "data=journal"},  	{Opt_data_ordered, "data=ordered"}, @@ -868,7 +898,7 @@ static ext3_fsblk_t get_sb_block(void **data, struct super_block *sb)  	/*todo: use simple_strtoll with >32bit ext3 */  	sb_block = simple_strtoul(options, &options, 0);  	if (*options && *options != ',') { -		ext3_msg(sb, "error: invalid sb specification: %s", +		ext3_msg(sb, KERN_ERR, "error: invalid sb specification: %s",  		       (char *) *data);  		return 1;  	} @@ -897,21 +927,24 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)  			"Not enough memory for storing quotafile name");  		return 0;  	} -	if (sbi->s_qf_names[qtype] && -		strcmp(sbi->s_qf_names[qtype], qname)) { -		ext3_msg(sb, KERN_ERR, -			"%s quota file already specified", QTYPE2NAME(qtype)); +	if (sbi->s_qf_names[qtype]) { +		int same = !strcmp(sbi->s_qf_names[qtype], qname); +  		kfree(qname); -		return 0; +		if (!same) { +			ext3_msg(sb, KERN_ERR, +				 "%s quota file already specified", +				 QTYPE2NAME(qtype)); +		} +		return same;  	} -	sbi->s_qf_names[qtype] = qname; -	if (strchr(sbi->s_qf_names[qtype], '/')) { +	if (strchr(qname, '/')) {  		ext3_msg(sb, KERN_ERR,  			"quotafile must be on filesystem root"); -		kfree(sbi->s_qf_names[qtype]); -		sbi->s_qf_names[qtype] = NULL; +		kfree(qname);  		return 0;  	} +	sbi->s_qf_names[qtype] = qname;  	set_opt(sbi->s_mount_opt, QUOTA);  	return 1;  } @@ -926,11 +959,10 @@ static int clear_qf_name(struct super_block *sb, int qtype) {  			" when quota turned on");  		return 0;  	} -	/* -	 * The space will be released later when all options are confirmed -	 * to be correct -	 */ -	sbi->s_qf_names[qtype] = NULL; +	if (sbi->s_qf_names[qtype]) { +		kfree(sbi->s_qf_names[qtype]); +		sbi->s_qf_names[qtype] = NULL; +	}  	return 1;  }  #endif @@ -944,6 +976,13 @@ static int parse_options (char *options, struct super_block *sb,  	substring_t args[MAX_OPT_ARGS];  	int data_opt = 0;  	int option; +	kuid_t uid; +	kgid_t gid; +	char *journal_path; +	struct inode *journal_inode; +	struct path path; +	int error; +  #ifdef CONFIG_QUOTA  	int qfmt;  #endif @@ -959,7 +998,7 @@ static int parse_options (char *options, struct super_block *sb,  		 * Initialize args struct so we know whether arg was  		 * found; some options take optional arguments.  		 */ -		args[0].to = args[0].from = 0; +		args[0].to = args[0].from = NULL;  		token = match_token(p, tokens, args);  		switch (token) {  		case Opt_bsd_df: @@ -977,12 +1016,23 @@ static int parse_options (char *options, struct super_block *sb,  		case Opt_resuid:  			if (match_int(&args[0], &option))  				return 0; -			sbi->s_resuid = option; +			uid = make_kuid(current_user_ns(), option); +			if (!uid_valid(uid)) { +				ext3_msg(sb, KERN_ERR, "Invalid uid value %d", option); +				return 0; + +			} +			sbi->s_resuid = uid;  			break;  		case Opt_resgid:  			if (match_int(&args[0], &option))  				return 0; -			sbi->s_resgid = option; +			gid = make_kgid(current_user_ns(), option); +			if (!gid_valid(gid)) { +				ext3_msg(sb, KERN_ERR, "Invalid gid value %d", option); +				return 0; +			} +			sbi->s_resgid = gid;  			break;  		case Opt_sb:  			/* handled by get_sb_block() instead of here */ @@ -1013,10 +1063,12 @@ static int parse_options (char *options, struct super_block *sb,  			set_opt (sbi->s_mount_opt, DEBUG);  			break;  		case Opt_oldalloc: -			set_opt (sbi->s_mount_opt, OLDALLOC); +			ext3_msg(sb, KERN_WARNING, +				"Ignoring deprecated oldalloc option");  			break;  		case Opt_orlov: -			clear_opt (sbi->s_mount_opt, OLDALLOC); +			ext3_msg(sb, KERN_WARNING, +				"Ignoring deprecated orlov option");  			break;  #ifdef CONFIG_EXT3_FS_XATTR  		case Opt_user_xattr: @@ -1085,6 +1137,41 @@ static int parse_options (char *options, struct super_block *sb,  				return 0;  			*journal_devnum = option;  			break; +		case Opt_journal_path: +			if (is_remount) { +				ext3_msg(sb, KERN_ERR, "error: cannot specify " +				       "journal on remount"); +				return 0; +			} + +			journal_path = match_strdup(&args[0]); +			if (!journal_path) { +				ext3_msg(sb, KERN_ERR, "error: could not dup " +					"journal device string"); +				return 0; +			} + +			error = kern_path(journal_path, LOOKUP_FOLLOW, &path); +			if (error) { +				ext3_msg(sb, KERN_ERR, "error: could not find " +					"journal device path: error %d", error); +				kfree(journal_path); +				return 0; +			} + +			journal_inode = path.dentry->d_inode; +			if (!S_ISBLK(journal_inode->i_mode)) { +				ext3_msg(sb, KERN_ERR, "error: journal path %s " +					"is not a block device", journal_path); +				path_put(&path); +				kfree(journal_path); +				return 0; +			} + +			*journal_devnum = new_encode_dev(journal_inode->i_rdev); +			path_put(&path); +			kfree(journal_path); +			break;  		case Opt_noload:  			set_opt (sbi->s_mount_opt, NOLOAD);  			break; @@ -1344,6 +1431,7 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,  	} else {  		ext3_msg(sb, KERN_INFO, "using internal journal");  	} +	cleancache_init_fs(sb);  	return res;  } @@ -1441,11 +1529,20 @@ static void ext3_orphan_cleanup (struct super_block * sb,  		return;  	} +	/* Check if feature set allows readwrite operations */ +	if (EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP)) { +		ext3_msg(sb, KERN_INFO, "Skipping orphan cleanup due to " +			 "unknown ROCOMPAT features"); +		return; +	} +  	if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) { -		if (es->s_last_orphan) +		/* don't clear list on RO mount w/ errors */ +		if (es->s_last_orphan && !(s_flags & MS_RDONLY)) {  			jbd_debug(1, "Errors on filesystem, "  				  "clearing orphan list.\n"); -		es->s_last_orphan = 0; +			es->s_last_orphan = 0; +		}  		jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");  		return;  	} @@ -1617,9 +1714,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)  		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;  	blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); @@ -1683,9 +1777,11 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)  	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); +	sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); +	sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); +	/* enable barriers by default */ +	set_opt(sbi->s_mount_opt, BARRIER);  	set_opt(sbi->s_mount_opt, RESERVATION);  	if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, @@ -1842,13 +1938,15 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)  		goto failed_mount;  	} -	if (generic_check_addressable(sb->s_blocksize_bits, -				      le32_to_cpu(es->s_blocks_count))) { +	err = generic_check_addressable(sb->s_blocksize_bits, +					le32_to_cpu(es->s_blocks_count)); +	if (err) {  		ext3_msg(sb, KERN_ERR,  			"error: filesystem is too large to mount safely");  		if (sizeof(sector_t) < 8)  			ext3_msg(sb, KERN_ERR,  				"error: CONFIG_LBDAF not enabled"); +		ret = err;  		goto failed_mount;  	} @@ -1911,6 +2009,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)  	sb->s_qcop = &ext3_qctl_operations;  	sb->dq_op = &ext3_quota_operations;  #endif +	memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));  	INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */  	mutex_init(&sbi->s_orphan_lock);  	mutex_init(&sbi->s_resize_lock); @@ -1998,22 +2097,23 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)  		ext3_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck");  		goto failed_mount3;  	} -	sb->s_root = d_alloc_root(root); +	sb->s_root = d_make_root(root);  	if (!sb->s_root) {  		ext3_msg(sb, KERN_ERR, "error: get root dentry failed"); -		iput(root);  		ret = -ENOMEM;  		goto failed_mount3;  	} -	ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY); +	if (ext3_setup_super(sb, es, sb->s_flags & MS_RDONLY)) +		sb->s_flags |= MS_RDONLY;  	EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS;  	ext3_orphan_cleanup(sb, es);  	EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS; -	if (needs_recovery) +	if (needs_recovery) { +		ext3_mark_recovery_complete(sb, es);  		ext3_msg(sb, KERN_INFO, "recovery complete"); -	ext3_mark_recovery_complete(sb, es); +	}  	ext3_msg(sb, KERN_INFO, "mounted filesystem with %s data mode",  		test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal":  		test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": @@ -2136,13 +2236,6 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,  	if (bdev == NULL)  		return NULL; -	if (bd_claim(bdev, sb)) { -		ext3_msg(sb, KERN_ERR, -			"error: failed to claim external journal device"); -		blkdev_put(bdev, FMODE_READ|FMODE_WRITE); -		return NULL; -	} -  	blocksize = sb->s_blocksize;  	hblock = bdev_logical_block_size(bdev);  	if (blocksize < hblock) { @@ -2188,11 +2281,11 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,  		goto out_bdev;  	}  	journal->j_private = sb; -	ll_rw_block(READ, 1, &journal->j_sb_buffer); -	wait_on_buffer(journal->j_sb_buffer); -	if (!buffer_uptodate(journal->j_sb_buffer)) { -		ext3_msg(sb, KERN_ERR, "I/O error on journal device"); -		goto out_journal; +	if (!bh_uptodate_or_lock(journal->j_sb_buffer)) { +		if (bh_submit_read(journal->j_sb_buffer)) { +			ext3_msg(sb, KERN_ERR, "I/O error on journal device"); +			goto out_journal; +		}  	}  	if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) {  		ext3_msg(sb, KERN_ERR, @@ -2291,7 +2384,7 @@ static int ext3_load_journal(struct super_block *sb,  	EXT3_SB(sb)->s_journal = journal;  	ext3_clear_journal_err(sb, es); -	if (journal_devnum && +	if (!really_read_only && journal_devnum &&  	    journal_devnum != le32_to_cpu(es->s_journal_dev)) {  		es->s_journal_dev = cpu_to_le32(journal_devnum); @@ -2479,6 +2572,12 @@ static int ext3_sync_fs(struct super_block *sb, int wait)  {  	tid_t target; +	trace_ext3_sync_fs(sb, wait); +	/* +	 * Writeback quota in non-journalled quota case - journalled quota has +	 * no dirty dquots +	 */ +	dquot_writeback_dquots(sb, -1);  	if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) {  		if (wait)  			log_wait_commit(EXT3_SB(sb)->s_journal, target); @@ -2529,11 +2628,9 @@ out:  static int ext3_unfreeze(struct super_block *sb)  {  	if (!(sb->s_flags & MS_RDONLY)) { -		lock_super(sb);  		/* Reser the needs_recovery flag before the fs is unlocked. */  		EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);  		ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); -		unlock_super(sb);  		journal_unlock_updates(EXT3_SB(sb)->s_journal);  	}  	return 0; @@ -2552,8 +2649,9 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)  	int i;  #endif +	sync_filesystem(sb); +  	/* Store the original options */ -	lock_super(sb);  	old_sb_flags = sb->s_flags;  	old_opts.s_mount_opt = sbi->s_mount_opt;  	old_opts.s_resuid = sbi->s_resuid; @@ -2562,7 +2660,18 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)  #ifdef CONFIG_QUOTA  	old_opts.s_jquota_fmt = sbi->s_jquota_fmt;  	for (i = 0; i < MAXQUOTAS; i++) -		old_opts.s_qf_names[i] = sbi->s_qf_names[i]; +		if (sbi->s_qf_names[i]) { +			old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i], +							 GFP_KERNEL); +			if (!old_opts.s_qf_names[i]) { +				int j; + +				for (j = 0; j < i; j++) +					kfree(old_opts.s_qf_names[j]); +				return -ENOMEM; +			} +		} else +			old_opts.s_qf_names[i] = NULL;  #endif  	/* @@ -2626,13 +2735,13 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)  			/*  			 * If we have an unprocessed orphan list hanging  			 * around from a previously readonly bdev mount, -			 * require a full umount/remount for now. +			 * require a full umount & mount for now.  			 */  			if (es->s_last_orphan) {  				ext3_msg(sb, KERN_WARNING, "warning: couldn't "  				       "remount RDWR because of unprocessed "  				       "orphan inode list.  Please " -				       "umount/remount instead."); +				       "umount & mount instead.");  				err = -EINVAL;  				goto restore_opts;  			} @@ -2655,12 +2764,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)  #ifdef CONFIG_QUOTA  	/* Release old quota file names */  	for (i = 0; i < MAXQUOTAS; i++) -		if (old_opts.s_qf_names[i] && -		    old_opts.s_qf_names[i] != sbi->s_qf_names[i]) -			kfree(old_opts.s_qf_names[i]); +		kfree(old_opts.s_qf_names[i]);  #endif -	unlock_super(sb); -  	if (enable_quota)  		dquot_resume(sb, -1);  	return 0; @@ -2673,13 +2778,10 @@ restore_opts:  #ifdef CONFIG_QUOTA  	sbi->s_jquota_fmt = old_opts.s_jquota_fmt;  	for (i = 0; i < MAXQUOTAS; i++) { -		if (sbi->s_qf_names[i] && -		    old_opts.s_qf_names[i] != sbi->s_qf_names[i]) -			kfree(sbi->s_qf_names[i]); +		kfree(sbi->s_qf_names[i]);  		sbi->s_qf_names[i] = old_opts.s_qf_names[i];  	}  #endif -	unlock_super(sb);  	return err;  } @@ -2725,6 +2827,10 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)  		 * bitmap, and an inode table.  		 */  		overhead += ngroups * (2 + sbi->s_itb_per_group); + +		/* Add the journal blocks as well */ +                overhead += sbi->s_journal->j_maxlen; +  		sbi->s_overhead_last = overhead;  		smp_wmb();  		sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count); @@ -2761,7 +2867,7 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)  static inline struct inode *dquot_to_inode(struct dquot *dquot)  { -	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; +	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];  }  static int ext3_write_dquot(struct dquot *dquot) @@ -2859,27 +2965,20 @@ 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 *name) +			 struct path *path)  {  	int err; -	struct path path;  	if (!test_opt(sb, QUOTA))  		return -EINVAL; -	err = kern_path(name, LOOKUP_FOLLOW, &path); -	if (err) -		return err; -  	/* Quotafile not on the same filesystem? */ -	if (path.mnt->mnt_sb != sb) { -		path_put(&path); +	if (path->dentry->d_sb != sb)  		return -EXDEV; -	}  	/* Journaling quota? */  	if (EXT3_SB(sb)->s_qf_names[type]) {  		/* Quotafile not of fs root? */ -		if (path.dentry->d_parent != sb->s_root) +		if (path->dentry->d_parent != sb->s_root)  			ext3_msg(sb, KERN_WARNING,  				"warning: Quota file not on filesystem root. "  				"Journaled quota will not work."); @@ -2889,7 +2988,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,  	 * 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)) { +	if (ext3_should_journal_data(path->dentry->d_inode)) {  		/*  		 * We don't need to lock updates but journal_flush() could  		 * otherwise be livelocked... @@ -2897,20 +2996,16 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,  		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); +		if (err)  			return err; -		}  	} -	err = dquot_quota_on_path(sb, type, format_id, &path); -	path_put(&path); -	return err; +	return dquot_quota_on(sb, type, format_id, path);  }  /* Read data from quotafile - avoid pagecache and such because we cannot afford   * acquiring the locks... As quota files are never truncated and quota code - * itself serializes the operations (and noone else should touch the files) + * itself serializes the operations (and no one else should touch the files)   * we don't have to be afraid of races */  static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,  			       size_t len, loff_t off) @@ -2979,7 +3074,6 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,  			(unsigned long long)off, (unsigned long long)len);  		return -EIO;  	} -	mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);  	bh = ext3_bread(handle, inode, blk, 1, &err);  	if (!bh)  		goto out; @@ -3003,10 +3097,8 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,  	}  	brelse(bh);  out: -	if (err) { -		mutex_unlock(&inode->i_mutex); +	if (err)  		return err; -	}  	if (inode->i_size < off + len) {  		i_size_write(inode, off + len);  		EXT3_I(inode)->i_disksize = inode->i_size; @@ -3014,7 +3106,6 @@ out:  	inode->i_version++;  	inode->i_mtime = inode->i_ctime = CURRENT_TIME;  	ext3_mark_inode_dirty(handle, inode); -	mutex_unlock(&inode->i_mutex);  	return len;  } @@ -3033,6 +3124,7 @@ static struct file_system_type ext3_fs_type = {  	.kill_sb	= kill_block_super,  	.fs_flags	= FS_REQUIRES_DEV,  }; +MODULE_ALIAS_FS("ext3");  static int __init init_ext3_fs(void)  {  | 
