diff options
Diffstat (limited to 'fs/reiserfs/super.c')
| -rw-r--r-- | fs/reiserfs/super.c | 971 | 
1 files changed, 626 insertions, 345 deletions
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 3bf7a6457f4..a392cef6acc 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -16,9 +16,9 @@  #include <linux/vmalloc.h>  #include <linux/time.h>  #include <asm/uaccess.h> -#include <linux/reiserfs_fs.h> -#include <linux/reiserfs_acl.h> -#include <linux/reiserfs_xattr.h> +#include "reiserfs.h" +#include "acl.h" +#include "xattr.h"  #include <linux/init.h>  #include <linux/blkdev.h>  #include <linux/buffer_head.h> @@ -28,7 +28,7 @@  #include <linux/mount.h>  #include <linux/namei.h>  #include <linux/crc32.h> -#include <linux/smp_lock.h> +#include <linux/seq_file.h>  struct file_system_type reiserfs_fs_type; @@ -67,24 +67,67 @@ static int reiserfs_sync_fs(struct super_block *s, int wait)  {  	struct reiserfs_transaction_handle th; +	/* +	 * Writeback quota in non-journalled quota case - journalled quota has +	 * no dirty dquots +	 */ +	dquot_writeback_dquots(s, -1);  	reiserfs_write_lock(s);  	if (!journal_begin(&th, s, 1)) -		if (!journal_end_sync(&th, s, 1)) +		if (!journal_end_sync(&th))  			reiserfs_flush_old_commits(s); -	s->s_dirt = 0;	/* Even if it's not true. -			 * We'll loop forever in sync_supers otherwise */  	reiserfs_write_unlock(s);  	return 0;  } -static void reiserfs_write_super(struct super_block *s) +static void flush_old_commits(struct work_struct *work)  { +	struct reiserfs_sb_info *sbi; +	struct super_block *s; + +	sbi = container_of(work, struct reiserfs_sb_info, old_work.work); +	s = sbi->s_journal->j_work_sb; + +	spin_lock(&sbi->old_work_lock); +	sbi->work_queued = 0; +	spin_unlock(&sbi->old_work_lock); +  	reiserfs_sync_fs(s, 1);  } +void reiserfs_schedule_old_flush(struct super_block *s) +{ +	struct reiserfs_sb_info *sbi = REISERFS_SB(s); +	unsigned long delay; + +	if (s->s_flags & MS_RDONLY) +		return; + +	spin_lock(&sbi->old_work_lock); +	if (!sbi->work_queued) { +		delay = msecs_to_jiffies(dirty_writeback_interval * 10); +		queue_delayed_work(system_long_wq, &sbi->old_work, delay); +		sbi->work_queued = 1; +	} +	spin_unlock(&sbi->old_work_lock); +} + +static void cancel_old_flush(struct super_block *s) +{ +	struct reiserfs_sb_info *sbi = REISERFS_SB(s); + +	cancel_delayed_work_sync(&REISERFS_SB(s)->old_work); +	spin_lock(&sbi->old_work_lock); +	sbi->work_queued = 0; +	spin_unlock(&sbi->old_work_lock); +} +  static int reiserfs_freeze(struct super_block *s)  {  	struct reiserfs_transaction_handle th; + +	cancel_old_flush(s); +  	reiserfs_write_lock(s);  	if (!(s->s_flags & MS_RDONLY)) {  		int err = journal_begin(&th, s, 1); @@ -93,12 +136,11 @@ static int reiserfs_freeze(struct super_block *s)  		} else {  			reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),  						     1); -			journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); +			journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));  			reiserfs_block_writes(&th); -			journal_end_sync(&th, s, 1); +			journal_end_sync(&th);  		}  	} -	s->s_dirt = 0;  	reiserfs_write_unlock(s);  	return 0;  } @@ -111,13 +153,15 @@ static int reiserfs_unfreeze(struct super_block *s)  extern const struct in_core_key MAX_IN_CORE_KEY; -/* this is used to delete "save link" when there are no items of a -   file it points to. It can either happen if unlink is completed but -   "save unlink" removal, or if file has both unlink and truncate -   pending and as unlink completes first (because key of "save link" -   protecting unlink is bigger that a key lf "save link" which -   protects truncate), so there left no items to make truncate -   completion on */ +/* + * this is used to delete "save link" when there are no items of a + * file it points to. It can either happen if unlink is completed but + * "save unlink" removal, or if file has both unlink and truncate + * pending and as unlink completes first (because key of "save link" + * protecting unlink is bigger that a key lf "save link" which + * protects truncate), so there left no items to make truncate + * completion on + */  static int remove_save_link_only(struct super_block *s,  				 struct reiserfs_key *key, int oid_free)  { @@ -134,7 +178,7 @@ static int remove_save_link_only(struct super_block *s,  		/* removals are protected by direct items */  		reiserfs_release_objectid(&th, le32_to_cpu(key->k_objectid)); -	return journal_end(&th, s, JOURNAL_PER_BALANCE_CNT); +	return journal_end(&th);  }  #ifdef CONFIG_QUOTA @@ -200,6 +244,7 @@ static int finish_unfinished(struct super_block *s)  	done = 0;  	REISERFS_SB(s)->s_is_unlinked_ok = 1;  	while (!retval) { +		int depth;  		retval = search_item(s, &max_cpu_key, &path);  		if (retval != ITEM_NOT_FOUND) {  			reiserfs_error(s, "vs-2140", @@ -215,7 +260,7 @@ static int finish_unfinished(struct super_block *s)  			break;  		}  		item_pos--; -		ih = B_N_PITEM_HEAD(bh, item_pos); +		ih = item_head(bh, item_pos);  		if (le32_to_cpu(ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID)  			/* there are no "save" links anymore */ @@ -228,7 +273,7 @@ static int finish_unfinished(struct super_block *s)  			truncate = 0;  		/* reiserfs_iget needs k_dirid and k_objectid only */ -		item = B_I_PITEM(bh, ih); +		item = ih_item_body(bh, ih);  		obj_key.on_disk_key.k_dir_id = le32_to_cpu(*(__le32 *) item);  		obj_key.on_disk_key.k_objectid =  		    le32_to_cpu(ih->ih_key.k_objectid); @@ -239,8 +284,10 @@ static int finish_unfinished(struct super_block *s)  		inode = reiserfs_iget(s, &obj_key);  		if (!inode) { -			/* the unlink almost completed, it just did not manage to remove -			   "save" link and release objectid */ +			/* +			 * the unlink almost completed, it just did not +			 * manage to remove "save" link and release objectid +			 */  			reiserfs_warning(s, "vs-2180", "iget failed for %K",  					 &obj_key);  			retval = remove_save_link_only(s, &save_link_key, 1); @@ -255,13 +302,18 @@ static int finish_unfinished(struct super_block *s)  			retval = remove_save_link_only(s, &save_link_key, 0);  			continue;  		} +		depth = reiserfs_write_unlock_nested(inode->i_sb);  		dquot_initialize(inode); +		reiserfs_write_lock_nested(inode->i_sb, depth);  		if (truncate && S_ISDIR(inode->i_mode)) { -			/* We got a truncate request for a dir which is impossible. -			   The only imaginable way is to execute unfinished truncate request -			   then boot into old kernel, remove the file and create dir with -			   the same key. */ +			/* +			 * We got a truncate request for a dir which +			 * is impossible.  The only imaginable way is to +			 * execute unfinished truncate request then boot +			 * into old kernel, remove the file and create dir +			 * with the same key. +			 */  			reiserfs_warning(s, "green-2101",  					 "impossible truncate on a "  					 "directory %k. Please report", @@ -275,14 +327,16 @@ static int finish_unfinished(struct super_block *s)  		if (truncate) {  			REISERFS_I(inode)->i_flags |=  			    i_link_saved_truncate_mask; -			/* not completed truncate found. New size was committed together -			   with "save" link */ +			/* +			 * not completed truncate found. New size was +			 * committed together with "save" link +			 */  			reiserfs_info(s, "Truncating %k to %Ld ..",  				      INODE_PKEY(inode), inode->i_size); -			reiserfs_truncate_file(inode, -					       0 -					       /*don't update modification time */ -					       ); + +			/* don't update modification time */ +			reiserfs_truncate_file(inode, 0); +  			retval = remove_save_link(inode, truncate);  		} else {  			REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask; @@ -311,10 +365,12 @@ static int finish_unfinished(struct super_block *s)  #ifdef CONFIG_QUOTA  	/* Turn quotas off */ +	reiserfs_write_unlock(s);  	for (i = 0; i < MAXQUOTAS; i++) {  		if (sb_dqopt(s)->files[i] && quota_enabled[i])  			dquot_quota_off(s, i);  	} +	reiserfs_write_lock(s);  	if (ms_active_set)  		/* Restore the flag back */  		s->s_flags &= ~MS_ACTIVE; @@ -326,10 +382,12 @@ static int finish_unfinished(struct super_block *s)  	return retval;  } -/* to protect file being unlinked from getting lost we "safe" link files -   being unlinked. This link will be deleted in the same transaction with last -   item of file. mounting the filesystem we scan all these links and remove -   files which almost got lost */ +/* + * to protect file being unlinked from getting lost we "safe" link files + * being unlinked. This link will be deleted in the same transaction with last + * item of file. mounting the filesystem we scan all these links and remove + * files which almost got lost + */  void add_save_link(struct reiserfs_transaction_handle *th,  		   struct inode *inode, int truncate)  { @@ -394,7 +452,7 @@ void add_save_link(struct reiserfs_transaction_handle *th,  	/* body of "save" link */  	link = INODE_PKEY(inode)->k_dir_id; -	/* put "save" link inot tree, don't charge quota to anyone */ +	/* put "save" link into tree, don't charge quota to anyone */  	retval =  	    reiserfs_insert_item(th, &path, &key, &ih, NULL, (char *)&link);  	if (retval) { @@ -448,22 +506,27 @@ int remove_save_link(struct inode *inode, int truncate)  	} else  		REISERFS_I(inode)->i_flags &= ~i_link_saved_truncate_mask; -	return journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); +	return journal_end(&th);  }  static void reiserfs_kill_sb(struct super_block *s)  {  	if (REISERFS_SB(s)) { -		if (REISERFS_SB(s)->xattr_root) { -			d_invalidate(REISERFS_SB(s)->xattr_root); -			dput(REISERFS_SB(s)->xattr_root); -			REISERFS_SB(s)->xattr_root = NULL; -		} -		if (REISERFS_SB(s)->priv_root) { -			d_invalidate(REISERFS_SB(s)->priv_root); -			dput(REISERFS_SB(s)->priv_root); -			REISERFS_SB(s)->priv_root = NULL; -		} +		reiserfs_proc_info_done(s); +		/* +		 * Force any pending inode evictions to occur now. Any +		 * inodes to be removed that have extended attributes +		 * associated with them need to clean them up before +		 * we can release the extended attribute root dentries. +		 * shrink_dcache_for_umount will BUG if we don't release +		 * those before it's called so ->put_super is too late. +		 */ +		shrink_dcache_sb(s); + +		dput(REISERFS_SB(s)->xattr_root); +		REISERFS_SB(s)->xattr_root = NULL; +		dput(REISERFS_SB(s)->priv_root); +		REISERFS_SB(s)->priv_root = NULL;  	}  	kill_block_super(s); @@ -478,22 +541,23 @@ static void reiserfs_put_super(struct super_block *s)  	reiserfs_write_lock(s); -	if (s->s_dirt) -		reiserfs_write_super(s); - -	/* change file system state to current state if it was mounted with read-write permissions */ +	/* +	 * change file system state to current state if it was mounted +	 * with read-write permissions +	 */  	if (!(s->s_flags & MS_RDONLY)) {  		if (!journal_begin(&th, s, 10)) {  			reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),  						     1);  			set_sb_umount_state(SB_DISK_SUPER_BLOCK(s),  					    REISERFS_SB(s)->s_mount_state); -			journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); +			journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));  		}  	} -	/* note, journal_release checks for readonly mount, and can decide not -	 ** to do a journal_end +	/* +	 * note, journal_release checks for readonly mount, and can +	 * decide not to do a journal_end  	 */  	journal_release(&th, s); @@ -508,10 +572,9 @@ static void reiserfs_put_super(struct super_block *s)  				 REISERFS_SB(s)->reserved_blocks);  	} -	reiserfs_proc_info_done(s); -  	reiserfs_write_unlock(s);  	mutex_destroy(&REISERFS_SB(s)->lock); +	destroy_workqueue(REISERFS_SB(s)->commit_wq);  	kfree(s->s_fs_info);  	s->s_fs_info = NULL;  } @@ -530,11 +593,17 @@ static struct inode *reiserfs_alloc_inode(struct super_block *sb)  	return &ei->vfs_inode;  } -static void reiserfs_destroy_inode(struct inode *inode) +static void reiserfs_i_callback(struct rcu_head *head)  { +	struct inode *inode = container_of(head, struct inode, i_rcu);  	kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));  } +static void reiserfs_destroy_inode(struct inode *inode) +{ +	call_rcu(&inode->i_rcu, reiserfs_i_callback); +} +  static void init_once(void *foo)  {  	struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; @@ -543,7 +612,7 @@ static void init_once(void *foo)  	inode_init_once(&ei->vfs_inode);  } -static int init_inodecache(void) +static int __init init_inodecache(void)  {  	reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache",  						  sizeof(struct @@ -558,16 +627,20 @@ 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(reiserfs_inode_cachep);  }  /* we don't mark inodes dirty, we just log them */ -static void reiserfs_dirty_inode(struct inode *inode) +static void reiserfs_dirty_inode(struct inode *inode, int flags)  {  	struct reiserfs_transaction_handle th;  	int err = 0; -	int lock_depth;  	if (inode->i_sb->s_flags & MS_RDONLY) {  		reiserfs_warning(inode->i_sb, "clm-6006", @@ -575,20 +648,97 @@ static void reiserfs_dirty_inode(struct inode *inode)  				 inode->i_ino);  		return;  	} -	lock_depth = reiserfs_write_lock_once(inode->i_sb); +	reiserfs_write_lock(inode->i_sb); -	/* this is really only used for atime updates, so they don't have -	 ** to be included in O_SYNC or fsync +	/* +	 * this is really only used for atime updates, so they don't have +	 * to be included in O_SYNC or fsync  	 */  	err = journal_begin(&th, inode->i_sb, 1);  	if (err)  		goto out;  	reiserfs_update_sd(&th, inode); -	journal_end(&th, inode->i_sb, 1); +	journal_end(&th);  out: -	reiserfs_write_unlock_once(inode->i_sb, lock_depth); +	reiserfs_write_unlock(inode->i_sb); +} + +static int reiserfs_show_options(struct seq_file *seq, struct dentry *root) +{ +	struct super_block *s = root->d_sb; +	struct reiserfs_journal *journal = SB_JOURNAL(s); +	long opts = REISERFS_SB(s)->s_mount_opt; + +	if (opts & (1 << REISERFS_LARGETAIL)) +		seq_puts(seq, ",tails=on"); +	else if (!(opts & (1 << REISERFS_SMALLTAIL))) +		seq_puts(seq, ",notail"); +	/* tails=small is default so we don't show it */ + +	if (!(opts & (1 << REISERFS_BARRIER_FLUSH))) +		seq_puts(seq, ",barrier=none"); +	/* barrier=flush is default so we don't show it */ + +	if (opts & (1 << REISERFS_ERROR_CONTINUE)) +		seq_puts(seq, ",errors=continue"); +	else if (opts & (1 << REISERFS_ERROR_PANIC)) +		seq_puts(seq, ",errors=panic"); +	/* errors=ro is default so we don't show it */ + +	if (opts & (1 << REISERFS_DATA_LOG)) +		seq_puts(seq, ",data=journal"); +	else if (opts & (1 << REISERFS_DATA_WRITEBACK)) +		seq_puts(seq, ",data=writeback"); +	/* data=ordered is default so we don't show it */ + +	if (opts & (1 << REISERFS_ATTRS)) +		seq_puts(seq, ",attrs"); + +	if (opts & (1 << REISERFS_XATTRS_USER)) +		seq_puts(seq, ",user_xattr"); + +	if (opts & (1 << REISERFS_EXPOSE_PRIVROOT)) +		seq_puts(seq, ",expose_privroot"); + +	if (opts & (1 << REISERFS_POSIXACL)) +		seq_puts(seq, ",acl"); + +	if (REISERFS_SB(s)->s_jdev) +		seq_printf(seq, ",jdev=%s", REISERFS_SB(s)->s_jdev); + +	if (journal->j_max_commit_age != journal->j_default_max_commit_age) +		seq_printf(seq, ",commit=%d", journal->j_max_commit_age); + +#ifdef CONFIG_QUOTA +	if (REISERFS_SB(s)->s_qf_names[USRQUOTA]) +		seq_printf(seq, ",usrjquota=%s", REISERFS_SB(s)->s_qf_names[USRQUOTA]); +	else if (opts & (1 << REISERFS_USRQUOTA)) +		seq_puts(seq, ",usrquota"); +	if (REISERFS_SB(s)->s_qf_names[GRPQUOTA]) +		seq_printf(seq, ",grpjquota=%s", REISERFS_SB(s)->s_qf_names[GRPQUOTA]); +	else if (opts & (1 << REISERFS_GRPQUOTA)) +		seq_puts(seq, ",grpquota"); +	if (REISERFS_SB(s)->s_jquota_fmt) { +		if (REISERFS_SB(s)->s_jquota_fmt == QFMT_VFS_OLD) +			seq_puts(seq, ",jqfmt=vfsold"); +		else if (REISERFS_SB(s)->s_jquota_fmt == QFMT_VFS_V0) +			seq_puts(seq, ",jqfmt=vfsv0"); +	} +#endif + +	/* Block allocator options */ +	if (opts & (1 << REISERFS_NO_BORDER)) +		seq_puts(seq, ",block-allocator=noborder"); +	if (opts & (1 << REISERFS_NO_UNHASHED_RELOCATION)) +		seq_puts(seq, ",block-allocator=no_unhashed_relocation"); +	if (opts & (1 << REISERFS_HASHED_RELOCATION)) +		seq_puts(seq, ",block-allocator=hashed_relocation"); +	if (opts & (1 << REISERFS_TEST4)) +		seq_puts(seq, ",block-allocator=test4"); +	show_alloc_options(seq, s); +	return 0;  }  #ifdef CONFIG_QUOTA @@ -605,13 +755,12 @@ static const struct super_operations reiserfs_sops = {  	.dirty_inode = reiserfs_dirty_inode,  	.evict_inode = reiserfs_evict_inode,  	.put_super = reiserfs_put_super, -	.write_super = reiserfs_write_super,  	.sync_fs = reiserfs_sync_fs,  	.freeze_fs = reiserfs_freeze,  	.unfreeze_fs = reiserfs_unfreeze,  	.statfs = reiserfs_statfs,  	.remount_fs = reiserfs_remount, -	.show_options = generic_show_options, +	.show_options = reiserfs_show_options,  #ifdef CONFIG_QUOTA  	.quota_read = reiserfs_quota_read,  	.quota_write = reiserfs_quota_write, @@ -626,7 +775,7 @@ static int reiserfs_acquire_dquot(struct dquot *);  static int reiserfs_release_dquot(struct dquot *);  static int reiserfs_mark_dquot_dirty(struct dquot *);  static int reiserfs_write_info(struct super_block *, int); -static int reiserfs_quota_on(struct super_block *, int, int, char *); +static int reiserfs_quota_on(struct super_block *, int, int, struct path *);  static const struct dquot_operations reiserfs_quota_operations = {  	.write_dquot = reiserfs_write_dquot, @@ -656,31 +805,53 @@ static const struct export_operations reiserfs_export_ops = {  	.get_parent = reiserfs_get_parent,  }; -/* this struct is used in reiserfs_getopt () for containing the value for those -   mount options that have values rather than being toggles. */ +/* + * this struct is used in reiserfs_getopt () for containing the value for + * those mount options that have values rather than being toggles. + */  typedef struct {  	char *value; -	int setmask;		/* bitmask which is to set on mount_options bitmask when this -				   value is found, 0 is no bits are to be changed. */ -	int clrmask;		/* bitmask which is to clear on mount_options bitmask when  this -				   value is found, 0 is no bits are to be changed. This is -				   applied BEFORE setmask */ +	/* +	 * bitmask which is to set on mount_options bitmask +	 * when this value is found, 0 is no bits are to be changed. +	 */ +	int setmask; +	/* +	 * bitmask which is to clear on mount_options bitmask +	 * when this value is found, 0 is no bits are to be changed. +	 * This is applied BEFORE setmask +	 */ +	int clrmask;  } arg_desc_t;  /* Set this bit in arg_required to allow empty arguments */  #define REISERFS_OPT_ALLOWEMPTY 31 -/* this struct is used in reiserfs_getopt() for describing the set of reiserfs -   mount options */ +/* + * this struct is used in reiserfs_getopt() for describing the + * set of reiserfs mount options + */  typedef struct {  	char *option_name; -	int arg_required;	/* 0 if argument is not required, not 0 otherwise */ -	const arg_desc_t *values;	/* list of values accepted by an option */ -	int setmask;		/* bitmask which is to set on mount_options bitmask when this -				   value is found, 0 is no bits are to be changed. */ -	int clrmask;		/* bitmask which is to clear on mount_options bitmask when  this -				   value is found, 0 is no bits are to be changed. This is -				   applied BEFORE setmask */ + +	/* 0 if argument is not required, not 0 otherwise */ +	int arg_required; + +	/* list of values accepted by an option */ +	const arg_desc_t *values; + +	/* +	 * bitmask which is to set on mount_options bitmask +	 * when this value is found, 0 is no bits are to be changed. +	 */ +	int setmask; + +	/* +	 * bitmask which is to clear on mount_options bitmask +	 * when this value is found, 0 is no bits are to be changed. +	 * This is applied BEFORE setmask +	 */ +	int clrmask;  } opt_desc_t;  /* possible values for -o data= */ @@ -701,8 +872,10 @@ static const arg_desc_t barrier_mode[] = {  	{.value = NULL}  }; -/* possible values for "-o block-allocator=" and bits which are to be set in -   s_mount_opt of reiserfs specific part of in-core super block */ +/* + * possible values for "-o block-allocator=" and bits which are to be set in + * s_mount_opt of reiserfs specific part of in-core super block + */  static const arg_desc_t balloc[] = {  	{"noborder", 1 << REISERFS_NO_BORDER, 0},  	{"border", 0, 1 << REISERFS_NO_BORDER}, @@ -732,21 +905,25 @@ static const arg_desc_t error_actions[] = {  	{NULL, 0, 0},  }; -/* proceed only one option from a list *cur - string containing of mount options -   opts - array of options which are accepted -   opt_arg - if option is found and requires an argument and if it is specifed -   in the input - pointer to the argument is stored here -   bit_flags - if option requires to set a certain bit - it is set here -   return -1 if unknown option is found, opt->arg_required otherwise */ +/* + * proceed only one option from a list *cur - string containing of mount + * options + * opts - array of options which are accepted + * opt_arg - if option is found and requires an argument and if it is specifed + * in the input - pointer to the argument is stored here + * bit_flags - if option requires to set a certain bit - it is set here + * return -1 if unknown option is found, opt->arg_required otherwise + */  static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,  			   char **opt_arg, unsigned long *bit_flags)  {  	char *p; -	/* foo=bar, -	   ^   ^  ^ -	   |   |  +-- option_end -	   |   +-- arg_start -	   +-- option_start +	/* +	 * foo=bar, +	 * ^   ^  ^ +	 * |   |  +-- option_end +	 * |   +-- arg_start +	 * +-- option_start  	 */  	const opt_desc_t *opt;  	const arg_desc_t *arg; @@ -761,9 +938,12 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,  	}  	if (!strncmp(p, "alloc=", 6)) { -		/* Ugly special case, probably we should redo options parser so that -		   it can understand several arguments for some options, also so that -		   it can fill several bitfields with option values. */ +		/* +		 * Ugly special case, probably we should redo options +		 * parser so that it can understand several arguments for +		 * some options, also so that it can fill several bitfields +		 * with option values. +		 */  		if (reiserfs_parse_alloc_options(s, p + 6)) {  			return -1;  		} else { @@ -826,7 +1006,10 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,  		return -1;  	} -	/* move to the argument, or to next option if argument is not required */ +	/* +	 * move to the argument, or to next option if argument is not +	 * required +	 */  	p++;  	if (opt->arg_required @@ -863,12 +1046,20 @@ static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,  }  /* returns 0 if something is wrong in option string, 1 - otherwise */ -static int reiserfs_parse_options(struct super_block *s, char *options,	/* string given via mount's -o */ +static int reiserfs_parse_options(struct super_block *s, + +				  /* string given via mount's -o */ +				  char *options, + +				  /* +				   * after the parsing phase, contains the +				   * collection of bitflags defining what +				   * mount options were selected. +				   */  				  unsigned long *mount_options, -				  /* after the parsing phase, contains the -				     collection of bitflags defining what -				     mount options were selected. */ -				  unsigned long *blocks,	/* strtol-ed from NNN of resize=NNN */ + +				  /* strtol-ed from NNN of resize=NNN */ +				  unsigned long *blocks,  				  char **jdev_name,  				  unsigned int *commit_max_age,  				  char **qf_names, @@ -878,7 +1069,10 @@ static int reiserfs_parse_options(struct super_block *s, char *options,	/* strin  	char *arg = NULL;  	char *pos;  	opt_desc_t opts[] = { -		/* Compatibility stuff, so that -o notail for old setups still work */ +		/* +		 * Compatibility stuff, so that -o notail for old +		 * setups still work +		 */  		{"tails",.arg_required = 't',.values = tails},  		{"notail",.clrmask =  		 (1 << REISERFS_LARGETAIL) | (1 << REISERFS_SMALLTAIL)}, @@ -909,9 +1103,9 @@ static int reiserfs_parse_options(struct super_block *s, char *options,	/* strin  		{"jdev",.arg_required = 'j',.values = NULL},  		{"nolargeio",.arg_required = 'w',.values = NULL},  		{"commit",.arg_required = 'c',.values = NULL}, -		{"usrquota",.setmask = 1 << REISERFS_QUOTA}, -		{"grpquota",.setmask = 1 << REISERFS_QUOTA}, -		{"noquota",.clrmask = 1 << REISERFS_QUOTA}, +		{"usrquota",.setmask = 1 << REISERFS_USRQUOTA}, +		{"grpquota",.setmask = 1 << REISERFS_GRPQUOTA}, +		{"noquota",.clrmask = 1 << REISERFS_USRQUOTA | 1 << REISERFS_GRPQUOTA},  		{"errors",.arg_required = 'e',.values = error_actions},  		{"usrjquota",.arg_required =  		 'u' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL}, @@ -923,8 +1117,10 @@ static int reiserfs_parse_options(struct super_block *s, char *options,	/* strin  	*blocks = 0;  	if (!options || !*options) -		/* use default configuration: create tails, journaling on, no -		   conversion to newest format */ +		/* +		 * use default configuration: create tails, journaling on, no +		 * conversion to newest format +		 */  		return 1;  	for (pos = options; pos;) { @@ -977,7 +1173,8 @@ static int reiserfs_parse_options(struct super_block *s, char *options,	/* strin  		if (c == 'j') {  			if (arg && *arg && jdev_name) { -				if (*jdev_name) {	//Hm, already assigned? +				/* Hm, already assigned? */ +				if (*jdev_name) {  					reiserfs_warning(s, "super-6510",  							 "journal device was "  							 "already specified to " @@ -1015,8 +1212,7 @@ static int reiserfs_parse_options(struct super_block *s, char *options,	/* strin  							 "on filesystem root.");  					return 0;  				} -				qf_names[qtype] = -				    kmalloc(strlen(arg) + 1, GFP_KERNEL); +				qf_names[qtype] = kstrdup(arg, GFP_KERNEL);  				if (!qf_names[qtype]) {  					reiserfs_warning(s, "reiserfs-2502",  							 "not enough memory " @@ -1024,13 +1220,19 @@ static int reiserfs_parse_options(struct super_block *s, char *options,	/* strin  							 "quotafile name.");  					return 0;  				} -				strcpy(qf_names[qtype], arg); -				*mount_options |= 1 << REISERFS_QUOTA; +				if (qtype == USRQUOTA) +					*mount_options |= 1 << REISERFS_USRQUOTA; +				else +					*mount_options |= 1 << REISERFS_GRPQUOTA;  			} else {  				if (qf_names[qtype] !=  				    REISERFS_SB(s)->s_qf_names[qtype])  					kfree(qf_names[qtype]);  				qf_names[qtype] = NULL; +				if (qtype == USRQUOTA) +					*mount_options &= ~(1 << REISERFS_USRQUOTA); +				else +					*mount_options &= ~(1 << REISERFS_GRPQUOTA);  			}  		}  		if (c == 'f') { @@ -1069,9 +1271,10 @@ static int reiserfs_parse_options(struct super_block *s, char *options,	/* strin  				 "journaled quota format not specified.");  		return 0;  	} -	/* This checking is not precise wrt the quota type but for our purposes it is sufficient */ -	if (!(*mount_options & (1 << REISERFS_QUOTA)) -	    && sb_any_quota_loaded(s)) { +	if ((!(*mount_options & (1 << REISERFS_USRQUOTA)) && +	       sb_has_quota_loaded(s, USRQUOTA)) || +	    (!(*mount_options & (1 << REISERFS_GRPQUOTA)) && +	       sb_has_quota_loaded(s, GRPQUOTA))) {  		reiserfs_warning(s, "super-6516", "quota options must "  				 "be present when quota is turned on.");  		return 0; @@ -1158,7 +1361,8 @@ static void handle_quota_files(struct super_block *s, char **qf_names,  			kfree(REISERFS_SB(s)->s_qf_names[i]);  		REISERFS_SB(s)->s_qf_names[i] = qf_names[i];  	} -	REISERFS_SB(s)->s_jquota_fmt = *qfmt; +	if (*qfmt) +		REISERFS_SB(s)->s_jquota_fmt = *qfmt;  }  #endif @@ -1179,6 +1383,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)  	int i;  #endif +	sync_filesystem(s);  	reiserfs_write_lock(s);  #ifdef CONFIG_QUOTA @@ -1196,7 +1401,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)  				kfree(qf_names[i]);  #endif  		err = -EINVAL; -		goto out_err; +		goto out_err_unlock;  	}  #ifdef CONFIG_QUOTA  	handle_quota_files(s, qf_names, &qfmt); @@ -1219,10 +1424,13 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)  	safe_mask |= 1 << REISERFS_ERROR_RO;  	safe_mask |= 1 << REISERFS_ERROR_CONTINUE;  	safe_mask |= 1 << REISERFS_ERROR_PANIC; -	safe_mask |= 1 << REISERFS_QUOTA; +	safe_mask |= 1 << REISERFS_USRQUOTA; +	safe_mask |= 1 << REISERFS_GRPQUOTA; -	/* Update the bitmask, taking care to keep -	 * the bits we're not allowed to change here */ +	/* +	 * Update the bitmask, taking care to keep +	 * the bits we're not allowed to change here +	 */  	REISERFS_SB(s)->s_mount_opt =  	    (REISERFS_SB(s)->  	     s_mount_opt & ~safe_mask) | (mount_options & safe_mask); @@ -1239,15 +1447,16 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)  	if (blocks) {  		err = reiserfs_resize(s, blocks);  		if (err != 0) -			goto out_err; +			goto out_err_unlock;  	}  	if (*mount_flags & MS_RDONLY) { +		reiserfs_write_unlock(s);  		reiserfs_xattr_init(s, *mount_flags);  		/* remount read-only */  		if (s->s_flags & MS_RDONLY)  			/* it is read-only already */ -			goto out_ok; +			goto out_ok_unlocked;  		err = dquot_suspend(s, -1);  		if (err < 0) @@ -1256,36 +1465,41 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)  		/* try to remount file system with read-only permissions */  		if (sb_umount_state(rs) == REISERFS_VALID_FS  		    || REISERFS_SB(s)->s_mount_state != REISERFS_VALID_FS) { -			goto out_ok; +			goto out_ok_unlocked;  		} +		reiserfs_write_lock(s); +  		err = journal_begin(&th, s, 10);  		if (err) -			goto out_err; +			goto out_err_unlock;  		/* Mounting a rw partition read-only. */  		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);  		set_sb_umount_state(rs, REISERFS_SB(s)->s_mount_state); -		journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); +		journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));  	} else {  		/* remount read-write */  		if (!(s->s_flags & MS_RDONLY)) { +			reiserfs_write_unlock(s);  			reiserfs_xattr_init(s, *mount_flags); -			goto out_ok;	/* We are read-write already */ +			goto out_ok_unlocked;	/* We are read-write already */  		}  		if (reiserfs_is_journal_aborted(journal)) {  			err = journal->j_errno; -			goto out_err; +			goto out_err_unlock;  		}  		handle_data_mode(s, mount_options);  		handle_barrier_mode(s, mount_options);  		REISERFS_SB(s)->s_mount_state = sb_umount_state(rs); -		s->s_flags &= ~MS_RDONLY;	/* now it is safe to call journal_begin */ + +		/* now it is safe to call journal_begin */ +		s->s_flags &= ~MS_RDONLY;  		err = journal_begin(&th, s, 10);  		if (err) -			goto out_err; +			goto out_err_unlock;  		/* Mount a partition which is read-only, read-write */  		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); @@ -1295,30 +1509,32 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)  		if (!old_format_only(s))  			set_sb_mnt_count(rs, sb_mnt_count(rs) + 1);  		/* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */ -		journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); +		journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));  		REISERFS_SB(s)->s_mount_state = REISERFS_VALID_FS;  	}  	/* this will force a full flush of all journal lists */  	SB_JOURNAL(s)->j_must_wait = 1; -	err = journal_end(&th, s, 10); +	err = journal_end(&th);  	if (err) -		goto out_err; -	s->s_dirt = 0; +		goto out_err_unlock; +	reiserfs_write_unlock(s);  	if (!(*mount_flags & MS_RDONLY)) {  		dquot_resume(s, -1); +		reiserfs_write_lock(s);  		finish_unfinished(s); +		reiserfs_write_unlock(s);  		reiserfs_xattr_init(s, *mount_flags);  	} -out_ok: +out_ok_unlocked:  	replace_mount_options(s, new_opts); -	reiserfs_write_unlock(s);  	return 0; +out_err_unlock: +	reiserfs_write_unlock(s);  out_err:  	kfree(new_opts); -	reiserfs_write_unlock(s);  	return err;  } @@ -1332,7 +1548,7 @@ static int read_super_block(struct super_block *s, int offset)  	if (!bh) {  		reiserfs_warning(s, "sh-2006",  				 "bread failed (dev %s, block %lu, size %lu)", -				 reiserfs_bdevname(s), offset / s->s_blocksize, +				 s->s_id, offset / s->s_blocksize,  				 s->s_blocksize);  		return 1;  	} @@ -1342,9 +1558,9 @@ static int read_super_block(struct super_block *s, int offset)  		brelse(bh);  		return 1;  	} -	// -	// ok, reiserfs signature (old or new) found in at the given offset -	// +	/* +	 * ok, reiserfs signature (old or new) found in at the given offset +	 */  	fs_blocksize = sb_blocksize(rs);  	brelse(bh);  	sb_set_blocksize(s, fs_blocksize); @@ -1353,7 +1569,7 @@ static int read_super_block(struct super_block *s, int offset)  	if (!bh) {  		reiserfs_warning(s, "sh-2007",  				 "bread failed (dev %s, block %lu, size %lu)", -				 reiserfs_bdevname(s), offset / s->s_blocksize, +				 s->s_id, offset / s->s_blocksize,  				 s->s_blocksize);  		return 1;  	} @@ -1362,7 +1578,7 @@ static int read_super_block(struct super_block *s, int offset)  	if (sb_blocksize(rs) != s->s_blocksize) {  		reiserfs_warning(s, "sh-2011", "can't find a reiserfs "  				 "filesystem on (dev %s, block %Lu, size %lu)", -				 reiserfs_bdevname(s), +				 s->s_id,  				 (unsigned long long)bh->b_blocknr,  				 s->s_blocksize);  		brelse(bh); @@ -1382,9 +1598,11 @@ static int read_super_block(struct super_block *s, int offset)  	SB_BUFFER_WITH_SB(s) = bh;  	SB_DISK_SUPER_BLOCK(s) = rs; +	/* +	 * magic is of non-standard journal filesystem, look at s_version to +	 * find which format is in use +	 */  	if (is_reiserfs_jr(rs)) { -		/* magic is of non-standard journal filesystem, look at s_version to -		   find which format is in use */  		if (sb_version(rs) == REISERFS_VERSION_2)  			reiserfs_info(s, "found reiserfs format \"3.6\""  				      " with non-standard journal\n"); @@ -1398,8 +1616,10 @@ static int read_super_block(struct super_block *s, int offset)  			return 1;  		}  	} else -		/* s_version of standard format may contain incorrect information, -		   so we just look at the magic string */ +		/* +		 * s_version of standard format may contain incorrect +		 * information, so we just look at the magic string +		 */  		reiserfs_info(s,  			      "found reiserfs format \"%s\" with standard journal\n",  			      is_reiserfs_3_5(rs) ? "3.5" : "3.6"); @@ -1411,8 +1631,9 @@ static int read_super_block(struct super_block *s, int offset)  	s->dq_op = &reiserfs_quota_operations;  #endif -	/* new format is limited by the 32 bit wide i_blocks field, want to -	 ** be one full block below that. +	/* +	 * new format is limited by the 32 bit wide i_blocks field, want to +	 * be one full block below that.  	 */  	s->s_maxbytes = (512LL << 32) - s->s_blocksize;  	return 0; @@ -1421,10 +1642,8 @@ static int read_super_block(struct super_block *s, int offset)  /* after journal replay, reread all bitmap and super blocks */  static int reread_meta_blocks(struct super_block *s)  { -	ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s))); -	reiserfs_write_unlock(s); +	ll_rw_block(READ, 1, &SB_BUFFER_WITH_SB(s));  	wait_on_buffer(SB_BUFFER_WITH_SB(s)); -	reiserfs_write_lock(s);  	if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {  		reiserfs_warning(s, "reiserfs-2504", "error reading the super");  		return 1; @@ -1433,14 +1652,15 @@ static int reread_meta_blocks(struct super_block *s)  	return 0;  } -///////////////////////////////////////////////////// -// hash detection stuff +/* hash detection stuff */ -// if root directory is empty - we set default - Yura's - hash and -// warn about it -// FIXME: we look for only one name in a directory. If tea and yura -// bith have the same value - we ask user to send report to the -// mailing list +/* + * if root directory is empty - we set default - Yura's - hash and + * warn about it + * FIXME: we look for only one name in a directory. If tea and yura + * both have the same value - we ask user to send report to the + * mailing list + */  static __u32 find_hash_out(struct super_block *s)  {  	int retval; @@ -1448,92 +1668,83 @@ static __u32 find_hash_out(struct super_block *s)  	struct cpu_key key;  	INITIALIZE_PATH(path);  	struct reiserfs_dir_entry de; +	struct reiserfs_de_head *deh;  	__u32 hash = DEFAULT_HASH; +	__u32 deh_hashval, teahash, r5hash, yurahash;  	inode = s->s_root->d_inode; -	do {			// Some serious "goto"-hater was there ;) -		u32 teahash, r5hash, yurahash; +	make_cpu_key(&key, inode, ~0, TYPE_DIRENTRY, 3); +	retval = search_by_entry_key(s, &key, &path, &de); +	if (retval == IO_ERROR) { +		pathrelse(&path); +		return UNSET_HASH; +	} +	if (retval == NAME_NOT_FOUND) +		de.de_entry_num--; -		make_cpu_key(&key, inode, ~0, TYPE_DIRENTRY, 3); -		retval = search_by_entry_key(s, &key, &path, &de); -		if (retval == IO_ERROR) { -			pathrelse(&path); -			return UNSET_HASH; -		} -		if (retval == NAME_NOT_FOUND) -			de.de_entry_num--; -		set_de_name_and_namelen(&de); -		if (deh_offset(&(de.de_deh[de.de_entry_num])) == DOT_DOT_OFFSET) { -			/* allow override in this case */ -			if (reiserfs_rupasov_hash(s)) { -				hash = YURA_HASH; -			} -			reiserfs_info(s, "FS seems to be empty, autodetect " -					 "is using the default hash\n"); -			break; -		} -		r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen)); -		teahash = GET_HASH_VALUE(keyed_hash(de.de_name, de.de_namelen)); -		yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen)); -		if (((teahash == r5hash) -		     && -		     (GET_HASH_VALUE(deh_offset(&(de.de_deh[de.de_entry_num]))) -		      == r5hash)) || ((teahash == yurahash) -				      && (yurahash == -					  GET_HASH_VALUE(deh_offset -							 (& -							  (de. -							   de_deh[de. -								  de_entry_num]))))) -		    || ((r5hash == yurahash) -			&& (yurahash == -			    GET_HASH_VALUE(deh_offset -					   (&(de.de_deh[de.de_entry_num])))))) { -			reiserfs_warning(s, "reiserfs-2506", "Unable to " -					 "automatically detect hash function. " -					 "Please mount with -o " -					 "hash={tea,rupasov,r5}"); -			hash = UNSET_HASH; -			break; -		} -		if (GET_HASH_VALUE(deh_offset(&(de.de_deh[de.de_entry_num]))) == -		    yurahash) +	set_de_name_and_namelen(&de); +	deh = de.de_deh + de.de_entry_num; + +	if (deh_offset(deh) == DOT_DOT_OFFSET) { +		/* allow override in this case */ +		if (reiserfs_rupasov_hash(s))  			hash = YURA_HASH; -		else if (GET_HASH_VALUE -			 (deh_offset(&(de.de_deh[de.de_entry_num]))) == teahash) -			hash = TEA_HASH; -		else if (GET_HASH_VALUE -			 (deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) -			hash = R5_HASH; -		else { -			reiserfs_warning(s, "reiserfs-2506", -					 "Unrecognised hash function"); -			hash = UNSET_HASH; -		} -	} while (0); +		reiserfs_info(s, "FS seems to be empty, autodetect is using the default hash\n"); +		goto out; +	} + +	deh_hashval = GET_HASH_VALUE(deh_offset(deh)); +	r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen)); +	teahash = GET_HASH_VALUE(keyed_hash(de.de_name, de.de_namelen)); +	yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen)); + +	if ((teahash == r5hash && deh_hashval == r5hash) || +	    (teahash == yurahash && deh_hashval == yurahash) || +	    (r5hash == yurahash && deh_hashval == yurahash)) { +		reiserfs_warning(s, "reiserfs-2506", +				 "Unable to automatically detect hash " +				 "function. Please mount with -o " +				 "hash={tea,rupasov,r5}"); +		hash = UNSET_HASH; +		goto out; +	} +	if (deh_hashval == yurahash) +		hash = YURA_HASH; +	else if (deh_hashval == teahash) +		hash = TEA_HASH; +	else if (deh_hashval == r5hash) +		hash = R5_HASH; +	else { +		reiserfs_warning(s, "reiserfs-2506", +				 "Unrecognised hash function"); +		hash = UNSET_HASH; +	} +out:  	pathrelse(&path);  	return hash;  } -// finds out which hash names are sorted with +/* finds out which hash names are sorted with */  static int what_hash(struct super_block *s)  {  	__u32 code;  	code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(s)); -	/* reiserfs_hash_detect() == true if any of the hash mount options -	 ** were used.  We must check them to make sure the user isn't -	 ** using a bad hash value +	/* +	 * reiserfs_hash_detect() == true if any of the hash mount options +	 * were used.  We must check them to make sure the user isn't +	 * using a bad hash value  	 */  	if (code == UNSET_HASH || reiserfs_hash_detect(s))  		code = find_hash_out(s);  	if (code != UNSET_HASH && reiserfs_hash_detect(s)) { -		/* detection has found the hash, and we must check against the -		 ** mount options +		/* +		 * detection has found the hash, and we must check against the +		 * mount options  		 */  		if (reiserfs_rupasov_hash(s) && code != YURA_HASH) {  			reiserfs_warning(s, "reiserfs-2507", @@ -1555,7 +1766,10 @@ static int what_hash(struct super_block *s)  			code = UNSET_HASH;  		}  	} else { -		/* find_hash_out was not called or could not determine the hash */ +		/* +		 * find_hash_out was not called or +		 * could not determine the hash +		 */  		if (reiserfs_rupasov_hash(s)) {  			code = YURA_HASH;  		} else if (reiserfs_tea_hash(s)) { @@ -1565,8 +1779,9 @@ static int what_hash(struct super_block *s)  		}  	} -	/* if we are mounted RW, and we have a new valid hash code, update -	 ** the super +	/* +	 * if we are mounted RW, and we have a new valid hash code, update +	 * the super  	 */  	if (code != UNSET_HASH &&  	    !(s->s_flags & MS_RDONLY) && @@ -1576,7 +1791,7 @@ static int what_hash(struct super_block *s)  	return code;  } -// return pointer to appropriate function +/* return pointer to appropriate function */  static hashf_t hash_function(struct super_block *s)  {  	switch (what_hash(s)) { @@ -1593,7 +1808,7 @@ static hashf_t hash_function(struct super_block *s)  	return NULL;  } -// this is used to set up correct value for old partitions +/* this is used to set up correct value for old partitions */  static int function2code(hashf_t func)  {  	if (func == keyed_hash) @@ -1603,7 +1818,7 @@ static int function2code(hashf_t func)  	if (func == r5_hash)  		return R5_HASH; -	BUG();			// should never happen +	BUG();			/* should never happen */  	return 0;  } @@ -1635,35 +1850,42 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  		return -ENOMEM;  	s->s_fs_info = sbi;  	/* Set default values for options: non-aggressive tails, RO on errors */ -	REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL); -	REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO); -	/* no preallocation minimum, be smart in -	   reiserfs_file_write instead */ -	REISERFS_SB(s)->s_alloc_options.preallocmin = 0; +	sbi->s_mount_opt |= (1 << REISERFS_SMALLTAIL); +	sbi->s_mount_opt |= (1 << REISERFS_ERROR_RO); +	sbi->s_mount_opt |= (1 << REISERFS_BARRIER_FLUSH); +	/* no preallocation minimum, be smart in reiserfs_file_write instead */ +	sbi->s_alloc_options.preallocmin = 0;  	/* Preallocate by 16 blocks (17-1) at once */ -	REISERFS_SB(s)->s_alloc_options.preallocsize = 17; +	sbi->s_alloc_options.preallocsize = 17;  	/* setup default block allocator options */  	reiserfs_init_alloc_options(s); -	mutex_init(&REISERFS_SB(s)->lock); -	REISERFS_SB(s)->lock_depth = -1; +	spin_lock_init(&sbi->old_work_lock); +	INIT_DELAYED_WORK(&sbi->old_work, flush_old_commits); +	mutex_init(&sbi->lock); +	sbi->lock_depth = -1; -	/* -	 * This function is called with the bkl, which also was the old -	 * locking used here. -	 * do_journal_begin() will soon check if we hold the lock (ie: was the -	 * bkl). This is likely because do_journal_begin() has several another -	 * callers because at this time, it doesn't seem to be necessary to -	 * protect against anything. -	 * Anyway, let's be conservative and lock for now. -	 */ -	reiserfs_write_lock(s); +	sbi->commit_wq = alloc_workqueue("reiserfs/%s", WQ_MEM_RECLAIM, 0, +					 s->s_id); +	if (!sbi->commit_wq) { +		SWARN(silent, s, "", "Cannot allocate commit workqueue"); +		errval = -ENOMEM; +		goto error_unlocked; +	}  	jdev_name = NULL;  	if (reiserfs_parse_options -	    (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name, +	    (s, (char *)data, &sbi->s_mount_opt, &blocks, &jdev_name,  	     &commit_max_age, qf_names, &qfmt) == 0) { -		goto error; +		goto error_unlocked; +	} +	if (jdev_name && jdev_name[0]) { +		sbi->s_jdev = kstrdup(jdev_name, GFP_KERNEL); +		if (!sbi->s_jdev) { +			SWARN(silent, s, "", "Cannot allocate memory for " +				"journal device name"); +			goto error; +		}  	}  #ifdef CONFIG_QUOTA  	handle_quota_files(s, qf_names, &qfmt); @@ -1671,23 +1893,32 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  	if (blocks) {  		SWARN(silent, s, "jmacd-7", "resize option for remount only"); -		goto error; +		goto error_unlocked;  	} -	/* try old format (undistributed bitmap, super block in 8-th 1k block of a device) */ +	/* +	 * try old format (undistributed bitmap, super block in 8-th 1k +	 * block of a device) +	 */  	if (!read_super_block(s, REISERFS_OLD_DISK_OFFSET_IN_BYTES))  		old_format = 1; -	/* try new format (64-th 1k block), which can contain reiserfs super block */ + +	/* +	 * try new format (64-th 1k block), which can contain reiserfs +	 * super block +	 */  	else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) {  		SWARN(silent, s, "sh-2021", "can not find reiserfs on %s", -		      reiserfs_bdevname(s)); -		goto error; +		      s->s_id); +		goto error_unlocked;  	}  	rs = SB_DISK_SUPER_BLOCK(s); -	/* Let's do basic sanity check to verify that underlying device is not -	   smaller than the filesystem. If the check fails then abort and scream, -	   because bad stuff will happen otherwise. */ +	/* +	 * Let's do basic sanity check to verify that underlying device is not +	 * smaller than the filesystem. If the check fails then abort and +	 * scream, because bad stuff will happen otherwise. +	 */  	if (s->s_bdev && s->s_bdev->bd_inode  	    && i_size_read(s->s_bdev->bd_inode) <  	    sb_block_count(rs) * sb_blocksize(rs)) { @@ -1697,7 +1928,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  		      "or increase size of your LVM partition");  		SWARN(silent, s, "", "Or may be you forgot to "  		      "reboot after fdisk when it told you to"); -		goto error; +		goto error_unlocked;  	}  	sbi->s_mount_state = SB_REISERFS_STATE(s); @@ -1705,8 +1936,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  	if ((errval = reiserfs_init_bitmap_cache(s))) {  		SWARN(silent, s, "jmacd-8", "unable to read bitmap"); -		goto error; +		goto error_unlocked;  	} +  	errval = -EINVAL;  #ifdef CONFIG_REISERFS_CHECK  	SWARN(silent, s, "", "CONFIG_REISERFS_CHECK is set ON"); @@ -1716,7 +1948,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  	/* make data=ordered the default */  	if (!reiserfs_data_log(s) && !reiserfs_data_ordered(s) &&  	    !reiserfs_data_writeback(s)) { -		REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_DATA_ORDERED); +		sbi->s_mount_opt |= (1 << REISERFS_DATA_ORDERED);  	}  	if (reiserfs_data_log(s)) { @@ -1729,24 +1961,27 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  	if (reiserfs_barrier_flush(s)) {  		printk("reiserfs: using flush barriers\n");  	} -	// set_device_ro(s->s_dev, 1) ; +  	if (journal_init(s, jdev_name, old_format, commit_max_age)) {  		SWARN(silent, s, "sh-2022",  		      "unable to initialize journal space"); -		goto error; +		goto error_unlocked;  	} else { -		jinit_done = 1;	/* once this is set, journal_release must be called -				 ** if we error out of the mount -				 */ +		/* +		 * once this is set, journal_release must be called +		 * if we error out of the mount +		 */ +		jinit_done = 1;  	} +  	if (reread_meta_blocks(s)) {  		SWARN(silent, s, "jmacd-9",  		      "unable to reread meta blocks after journal init"); -		goto error; +		goto error_unlocked;  	}  	if (replay_only(s)) -		goto error; +		goto error_unlocked;  	if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) {  		SWARN(silent, s, "clm-7000", @@ -1757,23 +1992,31 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  	args.dirid = REISERFS_ROOT_PARENT_OBJECTID;  	root_inode =  	    iget5_locked(s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor, -			 reiserfs_init_locked_inode, (void *)(&args)); +			 reiserfs_init_locked_inode, (void *)&args);  	if (!root_inode) {  		SWARN(silent, s, "jmacd-10", "get root inode failed"); -		goto error; +		goto error_unlocked;  	} +	/* +	 * This path assumed to be called with the BKL in the old times. +	 * Now we have inherited the big reiserfs lock from it and many +	 * reiserfs helpers called in the mount path and elsewhere require +	 * this lock to be held even if it's not always necessary. Let's be +	 * conservative and hold it early. The window can be reduced after +	 * careful review of the code. +	 */ +	reiserfs_write_lock(s); +  	if (root_inode->i_state & I_NEW) {  		reiserfs_read_locked_inode(root_inode, &args);  		unlock_new_inode(root_inode);  	} -	s->s_root = d_alloc_root(root_inode); -	if (!s->s_root) { -		iput(root_inode); +	s->s_root = d_make_root(root_inode); +	if (!s->s_root)  		goto error; -	} -	// define and initialize hash function +	/* define and initialize hash function */  	sbi->s_hash_function = hash_function(s);  	if (sbi->s_hash_function == NULL) {  		dput(s->s_root); @@ -1783,11 +2026,11 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  	if (is_reiserfs_3_5(rs)  	    || (is_reiserfs_jr(rs) && SB_VERSION(s) == REISERFS_VERSION_1)) -		set_bit(REISERFS_3_5, &(sbi->s_properties)); +		set_bit(REISERFS_3_5, &sbi->s_properties);  	else if (old_format) -		set_bit(REISERFS_OLD_FORMAT, &(sbi->s_properties)); +		set_bit(REISERFS_OLD_FORMAT, &sbi->s_properties);  	else -		set_bit(REISERFS_3_6, &(sbi->s_properties)); +		set_bit(REISERFS_3_6, &sbi->s_properties);  	if (!(s->s_flags & MS_RDONLY)) { @@ -1802,10 +2045,12 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  		set_sb_umount_state(rs, REISERFS_ERROR_FS);  		set_sb_fs_state(rs, 0); -		/* Clear out s_bmap_nr if it would wrap. We can handle this +		/* +		 * Clear out s_bmap_nr if it would wrap. We can handle this  		 * case, but older revisions can't. This will cause the  		 * file system to fail mount on those older implementations, -		 * avoiding corruption. -jeffm */ +		 * avoiding corruption. -jeffm +		 */  		if (bmap_would_wrap(reiserfs_bmap_count(s)) &&  		    sb_bmap_nr(rs) != 0) {  			reiserfs_warning(s, "super-2030", "This file system " @@ -1818,8 +2063,10 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  		}  		if (old_format_only(s)) { -			/* filesystem of format 3.5 either with standard or non-standard -			   journal */ +			/* +			 * filesystem of format 3.5 either with standard +			 * or non-standard journal +			 */  			if (convert_reiserfs(s)) {  				/* and -o conv is given */  				if (!silent) @@ -1827,8 +2074,11 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  						      "converting 3.5 filesystem to the 3.6 format");  				if (is_reiserfs_3_5(rs)) -					/* put magic string of 3.6 format. 2.2 will not be able to -					   mount this filesystem anymore */ +					/* +					 * put magic string of 3.6 format. +					 * 2.2 will not be able to +					 * mount this filesystem anymore +					 */  					memcpy(rs->s_v1.s_magic,  					       reiserfs_3_6_magic_string,  					       sizeof @@ -1836,8 +2086,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  				set_sb_version(rs, REISERFS_VERSION_2);  				reiserfs_convert_objectid_map_v1(s); -				set_bit(REISERFS_3_6, &(sbi->s_properties)); -				clear_bit(REISERFS_3_5, &(sbi->s_properties)); +				set_bit(REISERFS_3_6, &sbi->s_properties); +				clear_bit(REISERFS_3_5, &sbi->s_properties);  			} else if (!silent) {  				reiserfs_info(s, "using 3.5.x disk format\n");  			} @@ -1845,36 +2095,44 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  			set_sb_mnt_count(rs, sb_mnt_count(rs) + 1); -		journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); -		errval = journal_end(&th, s, 1); +		journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s)); +		errval = journal_end(&th);  		if (errval) {  			dput(s->s_root);  			s->s_root = NULL;  			goto error;  		} +		reiserfs_write_unlock(s);  		if ((errval = reiserfs_lookup_privroot(s)) ||  		    (errval = reiserfs_xattr_init(s, s->s_flags))) {  			dput(s->s_root);  			s->s_root = NULL; -			goto error; +			goto error_unlocked;  		} +		reiserfs_write_lock(s); -		/* look for files which were to be removed in previous session */ +		/* +		 * look for files which were to be removed in previous session +		 */  		finish_unfinished(s);  	} else {  		if (old_format_only(s) && !silent) {  			reiserfs_info(s, "using 3.5.x disk format\n");  		} +		reiserfs_write_unlock(s);  		if ((errval = reiserfs_lookup_privroot(s)) ||  		    (errval = reiserfs_xattr_init(s, s->s_flags))) {  			dput(s->s_root);  			s->s_root = NULL; -			goto error; +			goto error_unlocked;  		} +		reiserfs_write_lock(s);  	} -	// mark hash in super block: it could be unset. overwrite should be ok +	/* +	 * mark hash in super block: it could be unset. overwrite should be ok +	 */  	set_sb_hash_function_code(rs, function2code(sbi->s_hash_function));  	handle_attrs(s); @@ -1889,11 +2147,17 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)  	return (0);  error: -	if (jinit_done) {	/* kill the commit thread, free journal ram */ +	reiserfs_write_unlock(s); + +error_unlocked: +	/* kill the commit thread, free journal ram */ +	if (jinit_done) { +		reiserfs_write_lock(s);  		journal_release_error(NULL, s); +		reiserfs_write_unlock(s);  	} -	reiserfs_write_unlock(s); +	cancel_delayed_work_sync(&REISERFS_SB(s)->old_work);  	reiserfs_free_bitmap_cache(s);  	if (SB_BUFFER_WITH_SB(s)) @@ -1934,6 +2198,7 @@ static int reiserfs_write_dquot(struct dquot *dquot)  {  	struct reiserfs_transaction_handle th;  	int ret, err; +	int depth;  	reiserfs_write_lock(dquot->dq_sb);  	ret = @@ -1941,13 +2206,13 @@ static int reiserfs_write_dquot(struct dquot *dquot)  			  REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));  	if (ret)  		goto out; +	depth = reiserfs_write_unlock_nested(dquot->dq_sb);  	ret = dquot_commit(dquot); -	err = -	    journal_end(&th, dquot->dq_sb, -			REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); +	reiserfs_write_lock_nested(dquot->dq_sb, depth); +	err = journal_end(&th);  	if (!ret && err)  		ret = err; -      out: +out:  	reiserfs_write_unlock(dquot->dq_sb);  	return ret;  } @@ -1956,6 +2221,7 @@ static int reiserfs_acquire_dquot(struct dquot *dquot)  {  	struct reiserfs_transaction_handle th;  	int ret, err; +	int depth;  	reiserfs_write_lock(dquot->dq_sb);  	ret = @@ -1963,13 +2229,13 @@ static int reiserfs_acquire_dquot(struct dquot *dquot)  			  REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));  	if (ret)  		goto out; +	depth = reiserfs_write_unlock_nested(dquot->dq_sb);  	ret = dquot_acquire(dquot); -	err = -	    journal_end(&th, dquot->dq_sb, -			REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); +	reiserfs_write_lock_nested(dquot->dq_sb, depth); +	err = journal_end(&th);  	if (!ret && err)  		ret = err; -      out: +out:  	reiserfs_write_unlock(dquot->dq_sb);  	return ret;  } @@ -1983,19 +2249,19 @@ static int reiserfs_release_dquot(struct dquot *dquot)  	ret =  	    journal_begin(&th, dquot->dq_sb,  			  REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); +	reiserfs_write_unlock(dquot->dq_sb);  	if (ret) {  		/* Release dquot anyway to avoid endless cycle in dqput() */  		dquot_release(dquot);  		goto out;  	}  	ret = dquot_release(dquot); -	err = -	    journal_end(&th, dquot->dq_sb, -			REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); +	reiserfs_write_lock(dquot->dq_sb); +	err = journal_end(&th);  	if (!ret && err)  		ret = err; -      out:  	reiserfs_write_unlock(dquot->dq_sb); +out:  	return ret;  } @@ -2014,17 +2280,20 @@ static int reiserfs_write_info(struct super_block *sb, int type)  {  	struct reiserfs_transaction_handle th;  	int ret, err; +	int depth;  	/* Data block + inode block */  	reiserfs_write_lock(sb);  	ret = journal_begin(&th, sb, 2);  	if (ret)  		goto out; +	depth = reiserfs_write_unlock_nested(sb);  	ret = dquot_commit_info(sb, type); -	err = journal_end(&th, sb, 2); +	reiserfs_write_lock_nested(sb, depth); +	err = journal_end(&th);  	if (!ret && err)  		ret = err; -      out: +out:  	reiserfs_write_unlock(sb);  	return ret;  } @@ -2042,26 +2311,29 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type)   * Standard function to be called on quota_on   */  static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, -			     char *name) +			     struct path *path)  {  	int err; -	struct path path;  	struct inode *inode;  	struct reiserfs_transaction_handle th; +	int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA; -	if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA))) -		return -EINVAL; +	reiserfs_write_lock(sb); +	if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) { +		err = -EINVAL; +		goto out; +	} -	err = kern_path(name, LOOKUP_FOLLOW, &path); -	if (err) -		return err;  	/* Quotafile not on the same filesystem? */ -	if (path.mnt->mnt_sb != sb) { +	if (path->dentry->d_sb != sb) {  		err = -EXDEV;  		goto out;  	} -	inode = path.dentry->d_inode; -	/* We must not pack tails for quota files on reiserfs for quota IO to work */ +	inode = path->dentry->d_inode; +	/* +	 * We must not pack tails for quota files on reiserfs for quota +	 * IO to work +	 */  	if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {  		err = reiserfs_unpack(inode, NULL);  		if (err) { @@ -2076,7 +2348,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,  	/* Journaling quota? */  	if (REISERFS_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)  			reiserfs_warning(sb, "super-6521",  				 "Quota file not on filesystem root. "  				 "Journalled quota will not work."); @@ -2091,20 +2363,23 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,  		err = journal_begin(&th, sb, 1);  		if (err)  			goto out; -		err = journal_end_sync(&th, sb, 1); +		err = journal_end_sync(&th);  		if (err)  			goto out;  	} -	err = dquot_quota_on_path(sb, type, format_id, &path); +	reiserfs_write_unlock(sb); +	return dquot_quota_on(sb, type, format_id, path);  out: -	path_put(&path); +	reiserfs_write_unlock(sb);  	return err;  } -/* Read data from quotafile - avoid pagecache and such because we cannot afford +/* + * 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) - * we don't have to be afraid of races */ + * itself serializes the operations (and no one else should touch the files) + * we don't have to be afraid of races + */  static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data,  				   size_t len, loff_t off)  { @@ -2125,7 +2400,10 @@ static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data,  		    sb->s_blocksize - offset <  		    toread ? sb->s_blocksize - offset : toread;  		tmp_bh.b_state = 0; -		/* Quota files are without tails so we can safely use this function */ +		/* +		 * Quota files are without tails so we can safely +		 * use this function +		 */  		reiserfs_write_lock(sb);  		err = reiserfs_get_block(inode, blk, &tmp_bh, 0);  		reiserfs_write_unlock(sb); @@ -2148,8 +2426,10 @@ static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data,  	return len;  } -/* Write to quotafile (we know the transaction is already started and has - * enough credits) */ +/* + * Write to quotafile (we know the transaction is already started and has + * enough credits) + */  static ssize_t reiserfs_quota_write(struct super_block *sb, int type,  				    const char *data, size_t len, loff_t off)  { @@ -2166,12 +2446,13 @@ static ssize_t reiserfs_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);  	while (towrite > 0) {  		tocopy = sb->s_blocksize - offset < towrite ?  		    sb->s_blocksize - offset : towrite;  		tmp_bh.b_state = 0; +		reiserfs_write_lock(sb);  		err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE); +		reiserfs_write_unlock(sb);  		if (err)  			goto out;  		if (offset || tocopy != sb->s_blocksize) @@ -2187,10 +2468,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,  		flush_dcache_page(bh->b_page);  		set_buffer_uptodate(bh);  		unlock_buffer(bh); +		reiserfs_write_lock(sb);  		reiserfs_prepare_for_journal(sb, bh, 1); -		journal_mark_dirty(current->journal_info, sb, bh); +		journal_mark_dirty(current->journal_info, bh);  		if (!journal_quota)  			reiserfs_add_ordered_list(inode, bh); +		reiserfs_write_unlock(sb);  		brelse(bh);  		offset = 0;  		towrite -= tocopy; @@ -2198,16 +2481,13 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,  		blk++;  	}  out: -	if (len == towrite) { -		mutex_unlock(&inode->i_mutex); +	if (len == towrite)  		return err; -	}  	if (inode->i_size < off + len - towrite)  		i_size_write(inode, off + len - towrite);  	inode->i_version++;  	inode->i_mtime = inode->i_ctime = CURRENT_TIME;  	mark_inode_dirty(inode); -	mutex_unlock(&inode->i_mutex);  	return len - towrite;  } @@ -2224,18 +2504,18 @@ static int __init init_reiserfs_fs(void)  {  	int ret; -	if ((ret = init_inodecache())) { +	ret = init_inodecache(); +	if (ret)  		return ret; -	}  	reiserfs_proc_info_global_init();  	ret = register_filesystem(&reiserfs_fs_type); +	if (ret) +		goto out; -	if (ret == 0) { -		return 0; -	} - +	return 0; +out:  	reiserfs_proc_info_global_done();  	destroy_inodecache(); @@ -2256,6 +2536,7 @@ struct file_system_type reiserfs_fs_type = {  	.kill_sb = reiserfs_kill_sb,  	.fs_flags = FS_REQUIRES_DEV,  }; +MODULE_ALIAS_FS("reiserfs");  MODULE_DESCRIPTION("ReiserFS journaled filesystem");  MODULE_AUTHOR("Hans Reiser <reiser@namesys.com>");  | 
