xref: /openbmc/linux/fs/reiserfs/super.c (revision 42954c37)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Trivial changes by Alan Cox to add the LFS fixes
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Trivial Changes:
71da177e4SLinus Torvalds  * Rights granted to Hans Reiser to redistribute under other terms providing
81da177e4SLinus Torvalds  * he accepts all liability including but not limited to patent, fitness
91da177e4SLinus Torvalds  * for purpose, and direct or indirect claims arising from failure to perform.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * NO WARRANTY
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/module.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
161da177e4SLinus Torvalds #include <linux/vmalloc.h>
171da177e4SLinus Torvalds #include <linux/time.h>
1817093991SFabian Frederick #include <linux/uaccess.h>
19f466c6fdSAl Viro #include "reiserfs.h"
20a3063ab8SAl Viro #include "acl.h"
21c45ac888SAl Viro #include "xattr.h"
221da177e4SLinus Torvalds #include <linux/init.h>
231da177e4SLinus Torvalds #include <linux/blkdev.h>
2466114cadSTejun Heo #include <linux/backing-dev.h>
251da177e4SLinus Torvalds #include <linux/buffer_head.h>
26a5694255SChristoph Hellwig #include <linux/exportfs.h>
2774abb989SJan Kara #include <linux/quotaops.h>
281da177e4SLinus Torvalds #include <linux/vfs.h>
291da177e4SLinus Torvalds #include <linux/mount.h>
301da177e4SLinus Torvalds #include <linux/namei.h>
31651d0623SColy Li #include <linux/crc32.h>
32c3aa0776SJan Kara #include <linux/seq_file.h>
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds struct file_system_type reiserfs_fs_type;
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds static const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING;
371da177e4SLinus Torvalds static const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;
381da177e4SLinus Torvalds static const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING;
391da177e4SLinus Torvalds 
is_reiserfs_3_5(struct reiserfs_super_block * rs)401da177e4SLinus Torvalds int is_reiserfs_3_5(struct reiserfs_super_block *rs)
411da177e4SLinus Torvalds {
421da177e4SLinus Torvalds 	return !strncmp(rs->s_v1.s_magic, reiserfs_3_5_magic_string,
431da177e4SLinus Torvalds 			strlen(reiserfs_3_5_magic_string));
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds 
is_reiserfs_3_6(struct reiserfs_super_block * rs)461da177e4SLinus Torvalds int is_reiserfs_3_6(struct reiserfs_super_block *rs)
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds 	return !strncmp(rs->s_v1.s_magic, reiserfs_3_6_magic_string,
491da177e4SLinus Torvalds 			strlen(reiserfs_3_6_magic_string));
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds 
is_reiserfs_jr(struct reiserfs_super_block * rs)521da177e4SLinus Torvalds int is_reiserfs_jr(struct reiserfs_super_block *rs)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds 	return !strncmp(rs->s_v1.s_magic, reiserfs_jr_magic_string,
551da177e4SLinus Torvalds 			strlen(reiserfs_jr_magic_string));
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
is_any_reiserfs_magic_string(struct reiserfs_super_block * rs)581da177e4SLinus Torvalds static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)
591da177e4SLinus Torvalds {
601da177e4SLinus Torvalds 	return (is_reiserfs_3_5(rs) || is_reiserfs_3_6(rs) ||
611da177e4SLinus Torvalds 		is_reiserfs_jr(rs));
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds static int reiserfs_remount(struct super_block *s, int *flags, char *data);
65726c3342SDavid Howells static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf);
661da177e4SLinus Torvalds 
reiserfs_sync_fs(struct super_block * s,int wait)671da177e4SLinus Torvalds static int reiserfs_sync_fs(struct super_block *s, int wait)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
705af7926fSChristoph Hellwig 
71a1177825SJan Kara 	/*
72a1177825SJan Kara 	 * Writeback quota in non-journalled quota case - journalled quota has
73a1177825SJan Kara 	 * no dirty dquots
74a1177825SJan Kara 	 */
75a1177825SJan Kara 	dquot_writeback_dquots(s, -1);
761da177e4SLinus Torvalds 	reiserfs_write_lock(s);
771da177e4SLinus Torvalds 	if (!journal_begin(&th, s, 1))
7858d85426SJeff Mahoney 		if (!journal_end_sync(&th))
791da177e4SLinus Torvalds 			reiserfs_flush_old_commits(s);
801da177e4SLinus Torvalds 	reiserfs_write_unlock(s);
811da177e4SLinus Torvalds 	return 0;
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds 
flush_old_commits(struct work_struct * work)84033369d1SArtem Bityutskiy static void flush_old_commits(struct work_struct *work)
851da177e4SLinus Torvalds {
86033369d1SArtem Bityutskiy 	struct reiserfs_sb_info *sbi;
87033369d1SArtem Bityutskiy 	struct super_block *s;
88033369d1SArtem Bityutskiy 
89033369d1SArtem Bityutskiy 	sbi = container_of(work, struct reiserfs_sb_info, old_work.work);
90033369d1SArtem Bityutskiy 	s = sbi->s_journal->j_work_sb;
91033369d1SArtem Bityutskiy 
921e0e653fSJan Kara 	/*
931e0e653fSJan Kara 	 * We need s_umount for protecting quota writeback. We have to use
941e0e653fSJan Kara 	 * trylock as reiserfs_cancel_old_flush() may be waiting for this work
951e0e653fSJan Kara 	 * to complete with s_umount held.
961e0e653fSJan Kara 	 */
971e0e653fSJan Kara 	if (!down_read_trylock(&s->s_umount)) {
981e0e653fSJan Kara 		/* Requeue work if we are not cancelling it */
991e0e653fSJan Kara 		spin_lock(&sbi->old_work_lock);
1001e0e653fSJan Kara 		if (sbi->work_queued == 1)
1011e0e653fSJan Kara 			queue_delayed_work(system_long_wq, &sbi->old_work, HZ);
1021e0e653fSJan Kara 		spin_unlock(&sbi->old_work_lock);
1031e0e653fSJan Kara 		return;
1041e0e653fSJan Kara 	}
105033369d1SArtem Bityutskiy 	spin_lock(&sbi->old_work_lock);
10671b0576bSJan Kara 	/* Avoid clobbering the cancel state... */
10771b0576bSJan Kara 	if (sbi->work_queued == 1)
108033369d1SArtem Bityutskiy 		sbi->work_queued = 0;
109033369d1SArtem Bityutskiy 	spin_unlock(&sbi->old_work_lock);
110033369d1SArtem Bityutskiy 
1111da177e4SLinus Torvalds 	reiserfs_sync_fs(s, 1);
1121e0e653fSJan Kara 	up_read(&s->s_umount);
1131da177e4SLinus Torvalds }
1141da177e4SLinus Torvalds 
reiserfs_schedule_old_flush(struct super_block * s)115033369d1SArtem Bityutskiy void reiserfs_schedule_old_flush(struct super_block *s)
116033369d1SArtem Bityutskiy {
117033369d1SArtem Bityutskiy 	struct reiserfs_sb_info *sbi = REISERFS_SB(s);
118033369d1SArtem Bityutskiy 	unsigned long delay;
119033369d1SArtem Bityutskiy 
12001777836SJan Kara 	/*
12101777836SJan Kara 	 * Avoid scheduling flush when sb is being shut down. It can race
12201777836SJan Kara 	 * with journal shutdown and free still queued delayed work.
12301777836SJan Kara 	 */
1241751e8a6SLinus Torvalds 	if (sb_rdonly(s) || !(s->s_flags & SB_ACTIVE))
125033369d1SArtem Bityutskiy 		return;
126033369d1SArtem Bityutskiy 
127033369d1SArtem Bityutskiy 	spin_lock(&sbi->old_work_lock);
128033369d1SArtem Bityutskiy 	if (!sbi->work_queued) {
129033369d1SArtem Bityutskiy 		delay = msecs_to_jiffies(dirty_writeback_interval * 10);
130033369d1SArtem Bityutskiy 		queue_delayed_work(system_long_wq, &sbi->old_work, delay);
131033369d1SArtem Bityutskiy 		sbi->work_queued = 1;
132033369d1SArtem Bityutskiy 	}
133033369d1SArtem Bityutskiy 	spin_unlock(&sbi->old_work_lock);
134033369d1SArtem Bityutskiy }
135033369d1SArtem Bityutskiy 
reiserfs_cancel_old_flush(struct super_block * s)13671b0576bSJan Kara void reiserfs_cancel_old_flush(struct super_block *s)
137033369d1SArtem Bityutskiy {
138033369d1SArtem Bityutskiy 	struct reiserfs_sb_info *sbi = REISERFS_SB(s);
139033369d1SArtem Bityutskiy 
140033369d1SArtem Bityutskiy 	spin_lock(&sbi->old_work_lock);
14171b0576bSJan Kara 	/* Make sure no new flushes will be queued */
14271b0576bSJan Kara 	sbi->work_queued = 2;
143033369d1SArtem Bityutskiy 	spin_unlock(&sbi->old_work_lock);
14471b0576bSJan Kara 	cancel_delayed_work_sync(&REISERFS_SB(s)->old_work);
145033369d1SArtem Bityutskiy }
146033369d1SArtem Bityutskiy 
reiserfs_freeze(struct super_block * s)147c4be0c1dSTakashi Sato static int reiserfs_freeze(struct super_block *s)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
150033369d1SArtem Bityutskiy 
15171b0576bSJan Kara 	reiserfs_cancel_old_flush(s);
152033369d1SArtem Bityutskiy 
1531da177e4SLinus Torvalds 	reiserfs_write_lock(s);
154bc98a42cSDavid Howells 	if (!sb_rdonly(s)) {
1551da177e4SLinus Torvalds 		int err = journal_begin(&th, s, 1);
1561da177e4SLinus Torvalds 		if (err) {
1571da177e4SLinus Torvalds 			reiserfs_block_writes(&th);
1581da177e4SLinus Torvalds 		} else {
159bd4c625cSLinus Torvalds 			reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
160bd4c625cSLinus Torvalds 						     1);
16109f1b80bSJeff Mahoney 			journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));
1621da177e4SLinus Torvalds 			reiserfs_block_writes(&th);
16358d85426SJeff Mahoney 			journal_end_sync(&th);
1641da177e4SLinus Torvalds 		}
1651da177e4SLinus Torvalds 	}
1661da177e4SLinus Torvalds 	reiserfs_write_unlock(s);
167c4be0c1dSTakashi Sato 	return 0;
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
reiserfs_unfreeze(struct super_block * s)170c4be0c1dSTakashi Sato static int reiserfs_unfreeze(struct super_block *s)
171bd4c625cSLinus Torvalds {
17271b0576bSJan Kara 	struct reiserfs_sb_info *sbi = REISERFS_SB(s);
17371b0576bSJan Kara 
1741da177e4SLinus Torvalds 	reiserfs_allow_writes(s);
17571b0576bSJan Kara 	spin_lock(&sbi->old_work_lock);
17671b0576bSJan Kara 	/* Allow old_work to run again */
17771b0576bSJan Kara 	sbi->work_queued = 0;
17871b0576bSJan Kara 	spin_unlock(&sbi->old_work_lock);
179c4be0c1dSTakashi Sato 	return 0;
1801da177e4SLinus Torvalds }
1811da177e4SLinus Torvalds 
1826a3a16f2SAl Viro extern const struct in_core_key MAX_IN_CORE_KEY;
1831da177e4SLinus Torvalds 
184098297b2SJeff Mahoney /*
185098297b2SJeff Mahoney  * this is used to delete "save link" when there are no items of a
186098297b2SJeff Mahoney  * file it points to. It can either happen if unlink is completed but
187098297b2SJeff Mahoney  * "save unlink" removal, or if file has both unlink and truncate
188098297b2SJeff Mahoney  * pending and as unlink completes first (because key of "save link"
189098297b2SJeff Mahoney  * protecting unlink is bigger that a key lf "save link" which
190098297b2SJeff Mahoney  * protects truncate), so there left no items to make truncate
191098297b2SJeff Mahoney  * completion on
192098297b2SJeff Mahoney  */
remove_save_link_only(struct super_block * s,struct reiserfs_key * key,int oid_free)193bd4c625cSLinus Torvalds static int remove_save_link_only(struct super_block *s,
194bd4c625cSLinus Torvalds 				 struct reiserfs_key *key, int oid_free)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
1971da177e4SLinus Torvalds 	int err;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	/* we are going to do one balancing */
2001da177e4SLinus Torvalds 	err = journal_begin(&th, s, JOURNAL_PER_BALANCE_CNT);
2011da177e4SLinus Torvalds 	if (err)
2021da177e4SLinus Torvalds 		return err;
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	reiserfs_delete_solid_item(&th, NULL, key);
2051da177e4SLinus Torvalds 	if (oid_free)
2061da177e4SLinus Torvalds 		/* removals are protected by direct items */
2071da177e4SLinus Torvalds 		reiserfs_release_objectid(&th, le32_to_cpu(key->k_objectid));
2081da177e4SLinus Torvalds 
20958d85426SJeff Mahoney 	return journal_end(&th);
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
2131da177e4SLinus Torvalds static int reiserfs_quota_on_mount(struct super_block *, int);
2141da177e4SLinus Torvalds #endif
2151da177e4SLinus Torvalds 
216420902c9SMike Galbraith /*
217420902c9SMike Galbraith  * Look for uncompleted unlinks and truncates and complete them
218420902c9SMike Galbraith  *
219420902c9SMike Galbraith  * Called with superblock write locked.  If quotas are enabled, we have to
220420902c9SMike Galbraith  * release/retake lest we call dquot_quota_on_mount(), proceed to
221420902c9SMike Galbraith  * schedule_on_each_cpu() in invalidate_bdev() and deadlock waiting for the per
222420902c9SMike Galbraith  * cpu worklets to complete flush_async_commits() that in turn wait for the
223420902c9SMike Galbraith  * superblock write lock.
224420902c9SMike Galbraith  */
finish_unfinished(struct super_block * s)2251da177e4SLinus Torvalds static int finish_unfinished(struct super_block *s)
2261da177e4SLinus Torvalds {
2271da177e4SLinus Torvalds 	INITIALIZE_PATH(path);
2281da177e4SLinus Torvalds 	struct cpu_key max_cpu_key, obj_key;
229fb46f341SLepton Wu 	struct reiserfs_key save_link_key, last_inode_key;
2301da177e4SLinus Torvalds 	int retval = 0;
2311da177e4SLinus Torvalds 	struct item_head *ih;
2321da177e4SLinus Torvalds 	struct buffer_head *bh;
2331da177e4SLinus Torvalds 	int item_pos;
2341da177e4SLinus Torvalds 	char *item;
2351da177e4SLinus Torvalds 	int done;
2361da177e4SLinus Torvalds 	struct inode *inode;
2371da177e4SLinus Torvalds 	int truncate;
2381da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
2391da177e4SLinus Torvalds 	int i;
2401da177e4SLinus Torvalds 	int ms_active_set;
241aca60617SJan Kara 	int quota_enabled[REISERFS_MAXQUOTAS];
2421da177e4SLinus Torvalds #endif
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds 	/* compose key to look for "save" links */
2451da177e4SLinus Torvalds 	max_cpu_key.version = KEY_FORMAT_3_5;
246f359b74cSVladimir Saveliev 	max_cpu_key.on_disk_key.k_dir_id = ~0U;
247f359b74cSVladimir Saveliev 	max_cpu_key.on_disk_key.k_objectid = ~0U;
248f359b74cSVladimir Saveliev 	set_cpu_key_k_offset(&max_cpu_key, ~0U);
2491da177e4SLinus Torvalds 	max_cpu_key.key_length = 3;
2501da177e4SLinus Torvalds 
251fb46f341SLepton Wu 	memset(&last_inode_key, 0, sizeof(last_inode_key));
252fb46f341SLepton Wu 
2531da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
2541da177e4SLinus Torvalds 	/* Needed for iput() to work correctly and not trash data */
2551751e8a6SLinus Torvalds 	if (s->s_flags & SB_ACTIVE) {
2561da177e4SLinus Torvalds 		ms_active_set = 0;
2571da177e4SLinus Torvalds 	} else {
2581da177e4SLinus Torvalds 		ms_active_set = 1;
2591751e8a6SLinus Torvalds 		s->s_flags |= SB_ACTIVE;
2601da177e4SLinus Torvalds 	}
2611da177e4SLinus Torvalds 	/* Turn on quotas so that they are updated correctly */
262aca60617SJan Kara 	for (i = 0; i < REISERFS_MAXQUOTAS; i++) {
263f4b113aeSJan Kara 		quota_enabled[i] = 1;
2641da177e4SLinus Torvalds 		if (REISERFS_SB(s)->s_qf_names[i]) {
265f4b113aeSJan Kara 			int ret;
266f4b113aeSJan Kara 
267f4b113aeSJan Kara 			if (sb_has_quota_active(s, i)) {
268f4b113aeSJan Kara 				quota_enabled[i] = 0;
269f4b113aeSJan Kara 				continue;
270f4b113aeSJan Kara 			}
271420902c9SMike Galbraith 			reiserfs_write_unlock(s);
272f4b113aeSJan Kara 			ret = reiserfs_quota_on_mount(s, i);
273420902c9SMike Galbraith 			reiserfs_write_lock(s);
2741da177e4SLinus Torvalds 			if (ret < 0)
27545b03d5eSJeff Mahoney 				reiserfs_warning(s, "reiserfs-2500",
27645b03d5eSJeff Mahoney 						 "cannot turn on journaled "
27745b03d5eSJeff Mahoney 						 "quota: error %d", ret);
2781da177e4SLinus Torvalds 		}
2791da177e4SLinus Torvalds 	}
2801da177e4SLinus Torvalds #endif
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	done = 0;
2831da177e4SLinus Torvalds 	REISERFS_SB(s)->s_is_unlinked_ok = 1;
2841da177e4SLinus Torvalds 	while (!retval) {
285d2d0395fSJeff Mahoney 		int depth;
2861da177e4SLinus Torvalds 		retval = search_item(s, &max_cpu_key, &path);
2871da177e4SLinus Torvalds 		if (retval != ITEM_NOT_FOUND) {
2880030b645SJeff Mahoney 			reiserfs_error(s, "vs-2140",
2890030b645SJeff Mahoney 				       "search_by_key returned %d", retval);
2901da177e4SLinus Torvalds 			break;
2911da177e4SLinus Torvalds 		}
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 		bh = get_last_bh(&path);
2941da177e4SLinus Torvalds 		item_pos = get_item_pos(&path);
2951da177e4SLinus Torvalds 		if (item_pos != B_NR_ITEMS(bh)) {
29645b03d5eSJeff Mahoney 			reiserfs_warning(s, "vs-2060",
29745b03d5eSJeff Mahoney 					 "wrong position found");
2981da177e4SLinus Torvalds 			break;
2991da177e4SLinus Torvalds 		}
3001da177e4SLinus Torvalds 		item_pos--;
3014cf5f7adSJeff Mahoney 		ih = item_head(bh, item_pos);
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 		if (le32_to_cpu(ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID)
3041da177e4SLinus Torvalds 			/* there are no "save" links anymore */
3051da177e4SLinus Torvalds 			break;
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 		save_link_key = ih->ih_key;
3081da177e4SLinus Torvalds 		if (is_indirect_le_ih(ih))
3091da177e4SLinus Torvalds 			truncate = 1;
3101da177e4SLinus Torvalds 		else
3111da177e4SLinus Torvalds 			truncate = 0;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 		/* reiserfs_iget needs k_dirid and k_objectid only */
3144cf5f7adSJeff Mahoney 		item = ih_item_body(bh, ih);
3153e8962beSAl Viro 		obj_key.on_disk_key.k_dir_id = le32_to_cpu(*(__le32 *) item);
316bd4c625cSLinus Torvalds 		obj_key.on_disk_key.k_objectid =
317bd4c625cSLinus Torvalds 		    le32_to_cpu(ih->ih_key.k_objectid);
3186b9f5829SAl Viro 		obj_key.on_disk_key.k_offset = 0;
3196b9f5829SAl Viro 		obj_key.on_disk_key.k_type = 0;
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 		pathrelse(&path);
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 		inode = reiserfs_iget(s, &obj_key);
324ff7d080eSSudip Mukherjee 		if (IS_ERR_OR_NULL(inode)) {
325098297b2SJeff Mahoney 			/*
326098297b2SJeff Mahoney 			 * the unlink almost completed, it just did not
327098297b2SJeff Mahoney 			 * manage to remove "save" link and release objectid
328098297b2SJeff Mahoney 			 */
32945b03d5eSJeff Mahoney 			reiserfs_warning(s, "vs-2180", "iget failed for %K",
3301da177e4SLinus Torvalds 					 &obj_key);
3311da177e4SLinus Torvalds 			retval = remove_save_link_only(s, &save_link_key, 1);
3321da177e4SLinus Torvalds 			continue;
3331da177e4SLinus Torvalds 		}
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 		if (!truncate && inode->i_nlink) {
3361da177e4SLinus Torvalds 			/* file is not unlinked */
33745b03d5eSJeff Mahoney 			reiserfs_warning(s, "vs-2185",
33845b03d5eSJeff Mahoney 					 "file %K is not unlinked",
3391da177e4SLinus Torvalds 					 &obj_key);
3401da177e4SLinus Torvalds 			retval = remove_save_link_only(s, &save_link_key, 0);
3411da177e4SLinus Torvalds 			continue;
3421da177e4SLinus Torvalds 		}
343d2d0395fSJeff Mahoney 		depth = reiserfs_write_unlock_nested(inode->i_sb);
344871a2931SChristoph Hellwig 		dquot_initialize(inode);
345d2d0395fSJeff Mahoney 		reiserfs_write_lock_nested(inode->i_sb, depth);
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 		if (truncate && S_ISDIR(inode->i_mode)) {
348098297b2SJeff Mahoney 			/*
349098297b2SJeff Mahoney 			 * We got a truncate request for a dir which
350098297b2SJeff Mahoney 			 * is impossible.  The only imaginable way is to
351098297b2SJeff Mahoney 			 * execute unfinished truncate request then boot
352098297b2SJeff Mahoney 			 * into old kernel, remove the file and create dir
353098297b2SJeff Mahoney 			 * with the same key.
354098297b2SJeff Mahoney 			 */
35545b03d5eSJeff Mahoney 			reiserfs_warning(s, "green-2101",
35645b03d5eSJeff Mahoney 					 "impossible truncate on a "
35745b03d5eSJeff Mahoney 					 "directory %k. Please report",
358bd4c625cSLinus Torvalds 					 INODE_PKEY(inode));
3591da177e4SLinus Torvalds 			retval = remove_save_link_only(s, &save_link_key, 0);
3601da177e4SLinus Torvalds 			truncate = 0;
3611da177e4SLinus Torvalds 			iput(inode);
3621da177e4SLinus Torvalds 			continue;
3631da177e4SLinus Torvalds 		}
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 		if (truncate) {
366bd4c625cSLinus Torvalds 			REISERFS_I(inode)->i_flags |=
367bd4c625cSLinus Torvalds 			    i_link_saved_truncate_mask;
368098297b2SJeff Mahoney 			/*
369098297b2SJeff Mahoney 			 * not completed truncate found. New size was
370098297b2SJeff Mahoney 			 * committed together with "save" link
371098297b2SJeff Mahoney 			 */
37253872ed0SFabian Frederick 			reiserfs_info(s, "Truncating %k to %lld ..",
3731da177e4SLinus Torvalds 				      INODE_PKEY(inode), inode->i_size);
374098297b2SJeff Mahoney 
375bd4c625cSLinus Torvalds 			/* don't update modification time */
376098297b2SJeff Mahoney 			reiserfs_truncate_file(inode, 0);
377098297b2SJeff Mahoney 
3781da177e4SLinus Torvalds 			retval = remove_save_link(inode, truncate);
3791da177e4SLinus Torvalds 		} else {
3801da177e4SLinus Torvalds 			REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
3811da177e4SLinus Torvalds 			/* not completed unlink (rmdir) found */
3821da177e4SLinus Torvalds 			reiserfs_info(s, "Removing %k..", INODE_PKEY(inode));
383fb46f341SLepton Wu 			if (memcmp(&last_inode_key, INODE_PKEY(inode),
384fb46f341SLepton Wu 					sizeof(last_inode_key))){
385fb46f341SLepton Wu 				last_inode_key = *INODE_PKEY(inode);
3861da177e4SLinus Torvalds 				/* removal gets completed in iput */
3871da177e4SLinus Torvalds 				retval = 0;
388fb46f341SLepton Wu 			} else {
38945b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-2189", "Dead loop "
39045b03d5eSJeff Mahoney 						 "in finish_unfinished "
39145b03d5eSJeff Mahoney 						 "detected, just remove "
39245b03d5eSJeff Mahoney 						 "save link\n");
393fb46f341SLepton Wu 				retval = remove_save_link_only(s,
394fb46f341SLepton Wu 							&save_link_key, 0);
395fb46f341SLepton Wu 			}
3961da177e4SLinus Torvalds 		}
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 		iput(inode);
3991da177e4SLinus Torvalds 		printk("done\n");
4001da177e4SLinus Torvalds 		done++;
4011da177e4SLinus Torvalds 	}
4021da177e4SLinus Torvalds 	REISERFS_SB(s)->s_is_unlinked_ok = 0;
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
4051da177e4SLinus Torvalds 	/* Turn quotas off */
406d2d0395fSJeff Mahoney 	reiserfs_write_unlock(s);
407aca60617SJan Kara 	for (i = 0; i < REISERFS_MAXQUOTAS; i++) {
408f4b113aeSJan Kara 		if (sb_dqopt(s)->files[i] && quota_enabled[i])
409287a8095SChristoph Hellwig 			dquot_quota_off(s, i);
4101da177e4SLinus Torvalds 	}
411d2d0395fSJeff Mahoney 	reiserfs_write_lock(s);
4121da177e4SLinus Torvalds 	if (ms_active_set)
4131da177e4SLinus Torvalds 		/* Restore the flag back */
4141751e8a6SLinus Torvalds 		s->s_flags &= ~SB_ACTIVE;
4151da177e4SLinus Torvalds #endif
4161da177e4SLinus Torvalds 	pathrelse(&path);
4171da177e4SLinus Torvalds 	if (done)
4181da177e4SLinus Torvalds 		reiserfs_info(s, "There were %d uncompleted unlinks/truncates. "
4191da177e4SLinus Torvalds 			      "Completed\n", done);
4201da177e4SLinus Torvalds 	return retval;
4211da177e4SLinus Torvalds }
4221da177e4SLinus Torvalds 
423098297b2SJeff Mahoney /*
424098297b2SJeff Mahoney  * to protect file being unlinked from getting lost we "safe" link files
425098297b2SJeff Mahoney  * being unlinked. This link will be deleted in the same transaction with last
426098297b2SJeff Mahoney  * item of file. mounting the filesystem we scan all these links and remove
427098297b2SJeff Mahoney  * files which almost got lost
428098297b2SJeff Mahoney  */
add_save_link(struct reiserfs_transaction_handle * th,struct inode * inode,int truncate)4291da177e4SLinus Torvalds void add_save_link(struct reiserfs_transaction_handle *th,
4301da177e4SLinus Torvalds 		   struct inode *inode, int truncate)
4311da177e4SLinus Torvalds {
4321da177e4SLinus Torvalds 	INITIALIZE_PATH(path);
4331da177e4SLinus Torvalds 	int retval;
4341da177e4SLinus Torvalds 	struct cpu_key key;
4351da177e4SLinus Torvalds 	struct item_head ih;
4363e8962beSAl Viro 	__le32 link;
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	BUG_ON(!th->t_trans_id);
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds 	/* file can only get one "save link" of each kind */
4411da177e4SLinus Torvalds 	RFALSE(truncate &&
4421da177e4SLinus Torvalds 	       (REISERFS_I(inode)->i_flags & i_link_saved_truncate_mask),
4431da177e4SLinus Torvalds 	       "saved link already exists for truncated inode %lx",
4441da177e4SLinus Torvalds 	       (long)inode->i_ino);
4451da177e4SLinus Torvalds 	RFALSE(!truncate &&
4461da177e4SLinus Torvalds 	       (REISERFS_I(inode)->i_flags & i_link_saved_unlink_mask),
4471da177e4SLinus Torvalds 	       "saved link already exists for unlinked inode %lx",
4481da177e4SLinus Torvalds 	       (long)inode->i_ino);
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 	/* setup key of "save" link */
4511da177e4SLinus Torvalds 	key.version = KEY_FORMAT_3_5;
4521da177e4SLinus Torvalds 	key.on_disk_key.k_dir_id = MAX_KEY_OBJECTID;
4531da177e4SLinus Torvalds 	key.on_disk_key.k_objectid = inode->i_ino;
4541da177e4SLinus Torvalds 	if (!truncate) {
4551da177e4SLinus Torvalds 		/* unlink, rmdir, rename */
4561da177e4SLinus Torvalds 		set_cpu_key_k_offset(&key, 1 + inode->i_sb->s_blocksize);
4571da177e4SLinus Torvalds 		set_cpu_key_k_type(&key, TYPE_DIRECT);
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 		/* item head of "safe" link */
460bd4c625cSLinus Torvalds 		make_le_item_head(&ih, &key, key.version,
461bd4c625cSLinus Torvalds 				  1 + inode->i_sb->s_blocksize, TYPE_DIRECT,
4621da177e4SLinus Torvalds 				  4 /*length */ , 0xffff /*free space */ );
4631da177e4SLinus Torvalds 	} else {
4641da177e4SLinus Torvalds 		/* truncate */
4651da177e4SLinus Torvalds 		if (S_ISDIR(inode->i_mode))
46645b03d5eSJeff Mahoney 			reiserfs_warning(inode->i_sb, "green-2102",
46745b03d5eSJeff Mahoney 					 "Adding a truncate savelink for "
46845b03d5eSJeff Mahoney 					 "a directory %k! Please report",
469bd4c625cSLinus Torvalds 					 INODE_PKEY(inode));
4701da177e4SLinus Torvalds 		set_cpu_key_k_offset(&key, 1);
4711da177e4SLinus Torvalds 		set_cpu_key_k_type(&key, TYPE_INDIRECT);
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds 		/* item head of "safe" link */
4741da177e4SLinus Torvalds 		make_le_item_head(&ih, &key, key.version, 1, TYPE_INDIRECT,
4751da177e4SLinus Torvalds 				  4 /*length */ , 0 /*free space */ );
4761da177e4SLinus Torvalds 	}
4771da177e4SLinus Torvalds 	key.key_length = 3;
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds 	/* look for its place in the tree */
4801da177e4SLinus Torvalds 	retval = search_item(inode->i_sb, &key, &path);
4811da177e4SLinus Torvalds 	if (retval != ITEM_NOT_FOUND) {
4821da177e4SLinus Torvalds 		if (retval != -ENOSPC)
4830030b645SJeff Mahoney 			reiserfs_error(inode->i_sb, "vs-2100",
484bd4c625cSLinus Torvalds 				       "search_by_key (%K) returned %d", &key,
485bd4c625cSLinus Torvalds 				       retval);
4861da177e4SLinus Torvalds 		pathrelse(&path);
4871da177e4SLinus Torvalds 		return;
4881da177e4SLinus Torvalds 	}
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds 	/* body of "save" link */
4911da177e4SLinus Torvalds 	link = INODE_PKEY(inode)->k_dir_id;
4921da177e4SLinus Torvalds 
49325985edcSLucas De Marchi 	/* put "save" link into tree, don't charge quota to anyone */
494bd4c625cSLinus Torvalds 	retval =
495bd4c625cSLinus Torvalds 	    reiserfs_insert_item(th, &path, &key, &ih, NULL, (char *)&link);
4961da177e4SLinus Torvalds 	if (retval) {
4971da177e4SLinus Torvalds 		if (retval != -ENOSPC)
4980030b645SJeff Mahoney 			reiserfs_error(inode->i_sb, "vs-2120",
49945b03d5eSJeff Mahoney 				       "insert_item returned %d", retval);
5001da177e4SLinus Torvalds 	} else {
5011da177e4SLinus Torvalds 		if (truncate)
502bd4c625cSLinus Torvalds 			REISERFS_I(inode)->i_flags |=
503bd4c625cSLinus Torvalds 			    i_link_saved_truncate_mask;
5041da177e4SLinus Torvalds 		else
5051da177e4SLinus Torvalds 			REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
5061da177e4SLinus Torvalds 	}
5071da177e4SLinus Torvalds }
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds /* this opens transaction unlike add_save_link */
remove_save_link(struct inode * inode,int truncate)5101da177e4SLinus Torvalds int remove_save_link(struct inode *inode, int truncate)
5111da177e4SLinus Torvalds {
5121da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
5131da177e4SLinus Torvalds 	struct reiserfs_key key;
5141da177e4SLinus Torvalds 	int err;
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 	/* we are going to do one balancing only */
5171da177e4SLinus Torvalds 	err = journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
5181da177e4SLinus Torvalds 	if (err)
5191da177e4SLinus Torvalds 		return err;
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	/* setup key of "save" link */
5221da177e4SLinus Torvalds 	key.k_dir_id = cpu_to_le32(MAX_KEY_OBJECTID);
5231da177e4SLinus Torvalds 	key.k_objectid = INODE_PKEY(inode)->k_objectid;
5241da177e4SLinus Torvalds 	if (!truncate) {
5251da177e4SLinus Torvalds 		/* unlink, rmdir, rename */
5261da177e4SLinus Torvalds 		set_le_key_k_offset(KEY_FORMAT_3_5, &key,
5271da177e4SLinus Torvalds 				    1 + inode->i_sb->s_blocksize);
5281da177e4SLinus Torvalds 		set_le_key_k_type(KEY_FORMAT_3_5, &key, TYPE_DIRECT);
5291da177e4SLinus Torvalds 	} else {
5301da177e4SLinus Torvalds 		/* truncate */
5311da177e4SLinus Torvalds 		set_le_key_k_offset(KEY_FORMAT_3_5, &key, 1);
5321da177e4SLinus Torvalds 		set_le_key_k_type(KEY_FORMAT_3_5, &key, TYPE_INDIRECT);
5331da177e4SLinus Torvalds 	}
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 	if ((truncate &&
5361da177e4SLinus Torvalds 	     (REISERFS_I(inode)->i_flags & i_link_saved_truncate_mask)) ||
5371da177e4SLinus Torvalds 	    (!truncate &&
5381da177e4SLinus Torvalds 	     (REISERFS_I(inode)->i_flags & i_link_saved_unlink_mask)))
5391da177e4SLinus Torvalds 		/* don't take quota bytes from anywhere */
5401da177e4SLinus Torvalds 		reiserfs_delete_solid_item(&th, NULL, &key);
5411da177e4SLinus Torvalds 	if (!truncate) {
5421da177e4SLinus Torvalds 		reiserfs_release_objectid(&th, inode->i_ino);
5431da177e4SLinus Torvalds 		REISERFS_I(inode)->i_flags &= ~i_link_saved_unlink_mask;
5441da177e4SLinus Torvalds 	} else
5451da177e4SLinus Torvalds 		REISERFS_I(inode)->i_flags &= ~i_link_saved_truncate_mask;
5461da177e4SLinus Torvalds 
54758d85426SJeff Mahoney 	return journal_end(&th);
5481da177e4SLinus Torvalds }
5491da177e4SLinus Torvalds 
reiserfs_kill_sb(struct super_block * s)550edc666e2SDavid Howells static void reiserfs_kill_sb(struct super_block *s)
5511da177e4SLinus Torvalds {
552edc666e2SDavid Howells 	if (REISERFS_SB(s)) {
553672fe15dSAl Viro 		reiserfs_proc_info_done(s);
554a9e36da6SJeff Mahoney 		/*
555a9e36da6SJeff Mahoney 		 * Force any pending inode evictions to occur now. Any
556a9e36da6SJeff Mahoney 		 * inodes to be removed that have extended attributes
557a9e36da6SJeff Mahoney 		 * associated with them need to clean them up before
558a9e36da6SJeff Mahoney 		 * we can release the extended attribute root dentries.
559a9e36da6SJeff Mahoney 		 * shrink_dcache_for_umount will BUG if we don't release
560a9e36da6SJeff Mahoney 		 * those before it's called so ->put_super is too late.
561a9e36da6SJeff Mahoney 		 */
562a9e36da6SJeff Mahoney 		shrink_dcache_sb(s);
563a9e36da6SJeff Mahoney 
5641da177e4SLinus Torvalds 		dput(REISERFS_SB(s)->xattr_root);
565edc666e2SDavid Howells 		REISERFS_SB(s)->xattr_root = NULL;
5661da177e4SLinus Torvalds 		dput(REISERFS_SB(s)->priv_root);
567edc666e2SDavid Howells 		REISERFS_SB(s)->priv_root = NULL;
5681da177e4SLinus Torvalds 	}
569edc666e2SDavid Howells 
570edc666e2SDavid Howells 	kill_block_super(s);
571edc666e2SDavid Howells }
572edc666e2SDavid Howells 
57333eb928aSJan Kara #ifdef CONFIG_QUOTA
57433eb928aSJan Kara static int reiserfs_quota_off(struct super_block *sb, int type);
57533eb928aSJan Kara 
reiserfs_quota_off_umount(struct super_block * s)57633eb928aSJan Kara static void reiserfs_quota_off_umount(struct super_block *s)
57733eb928aSJan Kara {
57833eb928aSJan Kara 	int type;
57933eb928aSJan Kara 
58033eb928aSJan Kara 	for (type = 0; type < REISERFS_MAXQUOTAS; type++)
58133eb928aSJan Kara 		reiserfs_quota_off(s, type);
58233eb928aSJan Kara }
58333eb928aSJan Kara #else
reiserfs_quota_off_umount(struct super_block * s)58433eb928aSJan Kara static inline void reiserfs_quota_off_umount(struct super_block *s)
58533eb928aSJan Kara {
58633eb928aSJan Kara }
58733eb928aSJan Kara #endif
58833eb928aSJan Kara 
reiserfs_put_super(struct super_block * s)589edc666e2SDavid Howells static void reiserfs_put_super(struct super_block *s)
590edc666e2SDavid Howells {
591edc666e2SDavid Howells 	struct reiserfs_transaction_handle th;
592edc666e2SDavid Howells 	th.t_trans_id = 0;
5931da177e4SLinus Torvalds 
59433eb928aSJan Kara 	reiserfs_quota_off_umount(s);
595e0ccfd95SChristoph Hellwig 
5968ebc4232SFrederic Weisbecker 	reiserfs_write_lock(s);
5976cfd0148SChristoph Hellwig 
598098297b2SJeff Mahoney 	/*
599098297b2SJeff Mahoney 	 * change file system state to current state if it was mounted
600098297b2SJeff Mahoney 	 * with read-write permissions
601098297b2SJeff Mahoney 	 */
602bc98a42cSDavid Howells 	if (!sb_rdonly(s)) {
6031da177e4SLinus Torvalds 		if (!journal_begin(&th, s, 10)) {
604bd4c625cSLinus Torvalds 			reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
605bd4c625cSLinus Torvalds 						     1);
606bd4c625cSLinus Torvalds 			set_sb_umount_state(SB_DISK_SUPER_BLOCK(s),
607bd4c625cSLinus Torvalds 					    REISERFS_SB(s)->s_mount_state);
60809f1b80bSJeff Mahoney 			journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));
6091da177e4SLinus Torvalds 		}
6101da177e4SLinus Torvalds 	}
6111da177e4SLinus Torvalds 
612098297b2SJeff Mahoney 	/*
613098297b2SJeff Mahoney 	 * note, journal_release checks for readonly mount, and can
614098297b2SJeff Mahoney 	 * decide not to do a journal_end
6151da177e4SLinus Torvalds 	 */
6161da177e4SLinus Torvalds 	journal_release(&th, s);
6171da177e4SLinus Torvalds 
6185065227bSJeff Mahoney 	reiserfs_free_bitmap_cache(s);
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 	brelse(SB_BUFFER_WITH_SB(s));
6211da177e4SLinus Torvalds 
6221da177e4SLinus Torvalds 	print_statistics(s);
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds 	if (REISERFS_SB(s)->reserved_blocks != 0) {
62545b03d5eSJeff Mahoney 		reiserfs_warning(s, "green-2005", "reserved blocks left %d",
6261da177e4SLinus Torvalds 				 REISERFS_SB(s)->reserved_blocks);
6271da177e4SLinus Torvalds 	}
6281da177e4SLinus Torvalds 
6298ebc4232SFrederic Weisbecker 	reiserfs_write_unlock(s);
6308ebc4232SFrederic Weisbecker 	mutex_destroy(&REISERFS_SB(s)->lock);
631797d9016SJeff Mahoney 	destroy_workqueue(REISERFS_SB(s)->commit_wq);
6325474ca7dSJan Kara 	kfree(REISERFS_SB(s)->s_jdev);
6331da177e4SLinus Torvalds 	kfree(s->s_fs_info);
6341da177e4SLinus Torvalds 	s->s_fs_info = NULL;
6351da177e4SLinus Torvalds }
6361da177e4SLinus Torvalds 
637e18b890bSChristoph Lameter static struct kmem_cache *reiserfs_inode_cachep;
6381da177e4SLinus Torvalds 
reiserfs_alloc_inode(struct super_block * sb)6391da177e4SLinus Torvalds static struct inode *reiserfs_alloc_inode(struct super_block *sb)
6401da177e4SLinus Torvalds {
6411da177e4SLinus Torvalds 	struct reiserfs_inode_info *ei;
642fd60b288SMuchun Song 	ei = alloc_inode_sb(sb, reiserfs_inode_cachep, GFP_KERNEL);
6431da177e4SLinus Torvalds 	if (!ei)
6441da177e4SLinus Torvalds 		return NULL;
6450e4f6a79SAl Viro 	atomic_set(&ei->openers, 0);
6460e4f6a79SAl Viro 	mutex_init(&ei->tailpack);
64753873638SJan Kara #ifdef CONFIG_QUOTA
64853873638SJan Kara 	memset(&ei->i_dquot, 0, sizeof(ei->i_dquot));
64953873638SJan Kara #endif
65053873638SJan Kara 
6511da177e4SLinus Torvalds 	return &ei->vfs_inode;
6521da177e4SLinus Torvalds }
6531da177e4SLinus Torvalds 
reiserfs_free_inode(struct inode * inode)654a5a8cbeaSAl Viro static void reiserfs_free_inode(struct inode *inode)
655fa0d7e3dSNick Piggin {
656fa0d7e3dSNick Piggin 	kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));
657fa0d7e3dSNick Piggin }
658fa0d7e3dSNick Piggin 
init_once(void * foo)65951cc5068SAlexey Dobriyan static void init_once(void *foo)
6601da177e4SLinus Torvalds {
6611da177e4SLinus Torvalds 	struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo;
6621da177e4SLinus Torvalds 
6631da177e4SLinus Torvalds 	INIT_LIST_HEAD(&ei->i_prealloc_list);
6641da177e4SLinus Torvalds 	inode_init_once(&ei->vfs_inode);
6651da177e4SLinus Torvalds }
6661da177e4SLinus Torvalds 
init_inodecache(void)66731e14368SFabian Frederick static int __init init_inodecache(void)
6681da177e4SLinus Torvalds {
6691da177e4SLinus Torvalds 	reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache",
670bd4c625cSLinus Torvalds 						  sizeof(struct
671bd4c625cSLinus Torvalds 							 reiserfs_inode_info),
672fffb60f9SPaul Jackson 						  0, (SLAB_RECLAIM_ACCOUNT|
6735d097056SVladimir Davydov 						      SLAB_MEM_SPREAD|
6745d097056SVladimir Davydov 						      SLAB_ACCOUNT),
67520c2df83SPaul Mundt 						  init_once);
6761da177e4SLinus Torvalds 	if (reiserfs_inode_cachep == NULL)
6771da177e4SLinus Torvalds 		return -ENOMEM;
6781da177e4SLinus Torvalds 	return 0;
6791da177e4SLinus Torvalds }
6801da177e4SLinus Torvalds 
destroy_inodecache(void)6811da177e4SLinus Torvalds static void destroy_inodecache(void)
6821da177e4SLinus Torvalds {
6838c0a8537SKirill A. Shutemov 	/*
6848c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
6858c0a8537SKirill A. Shutemov 	 * destroy cache.
6868c0a8537SKirill A. Shutemov 	 */
6878c0a8537SKirill A. Shutemov 	rcu_barrier();
6881a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(reiserfs_inode_cachep);
6891da177e4SLinus Torvalds }
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds /* we don't mark inodes dirty, we just log them */
reiserfs_dirty_inode(struct inode * inode,int flags)692aa385729SChristoph Hellwig static void reiserfs_dirty_inode(struct inode *inode, int flags)
693bd4c625cSLinus Torvalds {
6941da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	int err = 0;
697dc8f6d89SFrederic Weisbecker 
698bc98a42cSDavid Howells 	if (sb_rdonly(inode->i_sb)) {
69945b03d5eSJeff Mahoney 		reiserfs_warning(inode->i_sb, "clm-6006",
70045b03d5eSJeff Mahoney 				 "writing inode %lu on readonly FS",
7011da177e4SLinus Torvalds 				 inode->i_ino);
7021da177e4SLinus Torvalds 		return;
7031da177e4SLinus Torvalds 	}
704278f6679SJeff Mahoney 	reiserfs_write_lock(inode->i_sb);
7051da177e4SLinus Torvalds 
706098297b2SJeff Mahoney 	/*
707098297b2SJeff Mahoney 	 * this is really only used for atime updates, so they don't have
708098297b2SJeff Mahoney 	 * to be included in O_SYNC or fsync
7091da177e4SLinus Torvalds 	 */
7101da177e4SLinus Torvalds 	err = journal_begin(&th, inode->i_sb, 1);
711dc8f6d89SFrederic Weisbecker 	if (err)
712dc8f6d89SFrederic Weisbecker 		goto out;
713dc8f6d89SFrederic Weisbecker 
7141da177e4SLinus Torvalds 	reiserfs_update_sd(&th, inode);
71558d85426SJeff Mahoney 	journal_end(&th);
716dc8f6d89SFrederic Weisbecker 
717dc8f6d89SFrederic Weisbecker out:
718278f6679SJeff Mahoney 	reiserfs_write_unlock(inode->i_sb);
7191da177e4SLinus Torvalds }
7201da177e4SLinus Torvalds 
reiserfs_show_options(struct seq_file * seq,struct dentry * root)721c3aa0776SJan Kara static int reiserfs_show_options(struct seq_file *seq, struct dentry *root)
722c3aa0776SJan Kara {
723c3aa0776SJan Kara 	struct super_block *s = root->d_sb;
724c3aa0776SJan Kara 	struct reiserfs_journal *journal = SB_JOURNAL(s);
725c3aa0776SJan Kara 	long opts = REISERFS_SB(s)->s_mount_opt;
726c3aa0776SJan Kara 
727c3aa0776SJan Kara 	if (opts & (1 << REISERFS_LARGETAIL))
728c3aa0776SJan Kara 		seq_puts(seq, ",tails=on");
729c3aa0776SJan Kara 	else if (!(opts & (1 << REISERFS_SMALLTAIL)))
730c3aa0776SJan Kara 		seq_puts(seq, ",notail");
731c3aa0776SJan Kara 	/* tails=small is default so we don't show it */
732c3aa0776SJan Kara 
733c3aa0776SJan Kara 	if (!(opts & (1 << REISERFS_BARRIER_FLUSH)))
734c3aa0776SJan Kara 		seq_puts(seq, ",barrier=none");
735c3aa0776SJan Kara 	/* barrier=flush is default so we don't show it */
736c3aa0776SJan Kara 
737c3aa0776SJan Kara 	if (opts & (1 << REISERFS_ERROR_CONTINUE))
738c3aa0776SJan Kara 		seq_puts(seq, ",errors=continue");
739c3aa0776SJan Kara 	else if (opts & (1 << REISERFS_ERROR_PANIC))
740c3aa0776SJan Kara 		seq_puts(seq, ",errors=panic");
741c3aa0776SJan Kara 	/* errors=ro is default so we don't show it */
742c3aa0776SJan Kara 
743c3aa0776SJan Kara 	if (opts & (1 << REISERFS_DATA_LOG))
744c3aa0776SJan Kara 		seq_puts(seq, ",data=journal");
745c3aa0776SJan Kara 	else if (opts & (1 << REISERFS_DATA_WRITEBACK))
746c3aa0776SJan Kara 		seq_puts(seq, ",data=writeback");
747c3aa0776SJan Kara 	/* data=ordered is default so we don't show it */
748c3aa0776SJan Kara 
749c3aa0776SJan Kara 	if (opts & (1 << REISERFS_ATTRS))
750c3aa0776SJan Kara 		seq_puts(seq, ",attrs");
751c3aa0776SJan Kara 
752c3aa0776SJan Kara 	if (opts & (1 << REISERFS_XATTRS_USER))
753c3aa0776SJan Kara 		seq_puts(seq, ",user_xattr");
754c3aa0776SJan Kara 
755c3aa0776SJan Kara 	if (opts & (1 << REISERFS_EXPOSE_PRIVROOT))
756c3aa0776SJan Kara 		seq_puts(seq, ",expose_privroot");
757c3aa0776SJan Kara 
758c3aa0776SJan Kara 	if (opts & (1 << REISERFS_POSIXACL))
759c3aa0776SJan Kara 		seq_puts(seq, ",acl");
760c3aa0776SJan Kara 
761c3aa0776SJan Kara 	if (REISERFS_SB(s)->s_jdev)
762a068acf2SKees Cook 		seq_show_option(seq, "jdev", REISERFS_SB(s)->s_jdev);
763c3aa0776SJan Kara 
764c3aa0776SJan Kara 	if (journal->j_max_commit_age != journal->j_default_max_commit_age)
765c3aa0776SJan Kara 		seq_printf(seq, ",commit=%d", journal->j_max_commit_age);
766c3aa0776SJan Kara 
767c3aa0776SJan Kara #ifdef CONFIG_QUOTA
768c3aa0776SJan Kara 	if (REISERFS_SB(s)->s_qf_names[USRQUOTA])
769a068acf2SKees Cook 		seq_show_option(seq, "usrjquota",
770a068acf2SKees Cook 				REISERFS_SB(s)->s_qf_names[USRQUOTA]);
771c3aa0776SJan Kara 	else if (opts & (1 << REISERFS_USRQUOTA))
772c3aa0776SJan Kara 		seq_puts(seq, ",usrquota");
773c3aa0776SJan Kara 	if (REISERFS_SB(s)->s_qf_names[GRPQUOTA])
774a068acf2SKees Cook 		seq_show_option(seq, "grpjquota",
775a068acf2SKees Cook 				REISERFS_SB(s)->s_qf_names[GRPQUOTA]);
776c3aa0776SJan Kara 	else if (opts & (1 << REISERFS_GRPQUOTA))
777c3aa0776SJan Kara 		seq_puts(seq, ",grpquota");
778c3aa0776SJan Kara 	if (REISERFS_SB(s)->s_jquota_fmt) {
779c3aa0776SJan Kara 		if (REISERFS_SB(s)->s_jquota_fmt == QFMT_VFS_OLD)
780c3aa0776SJan Kara 			seq_puts(seq, ",jqfmt=vfsold");
781c3aa0776SJan Kara 		else if (REISERFS_SB(s)->s_jquota_fmt == QFMT_VFS_V0)
782c3aa0776SJan Kara 			seq_puts(seq, ",jqfmt=vfsv0");
783c3aa0776SJan Kara 	}
784c3aa0776SJan Kara #endif
785c3aa0776SJan Kara 
786c3aa0776SJan Kara 	/* Block allocator options */
787c3aa0776SJan Kara 	if (opts & (1 << REISERFS_NO_BORDER))
788c3aa0776SJan Kara 		seq_puts(seq, ",block-allocator=noborder");
789c3aa0776SJan Kara 	if (opts & (1 << REISERFS_NO_UNHASHED_RELOCATION))
790c3aa0776SJan Kara 		seq_puts(seq, ",block-allocator=no_unhashed_relocation");
791c3aa0776SJan Kara 	if (opts & (1 << REISERFS_HASHED_RELOCATION))
792c3aa0776SJan Kara 		seq_puts(seq, ",block-allocator=hashed_relocation");
793c3aa0776SJan Kara 	if (opts & (1 << REISERFS_TEST4))
794c3aa0776SJan Kara 		seq_puts(seq, ",block-allocator=test4");
795c3aa0776SJan Kara 	show_alloc_options(seq, s);
796c3aa0776SJan Kara 	return 0;
797c3aa0776SJan Kara }
798c3aa0776SJan Kara 
7991da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
800bd4c625cSLinus Torvalds static ssize_t reiserfs_quota_write(struct super_block *, int, const char *,
801bd4c625cSLinus Torvalds 				    size_t, loff_t);
802bd4c625cSLinus Torvalds static ssize_t reiserfs_quota_read(struct super_block *, int, char *, size_t,
803bd4c625cSLinus Torvalds 				   loff_t);
80453873638SJan Kara 
reiserfs_get_dquots(struct inode * inode)805*42954c37SJan Kara static struct dquot __rcu **reiserfs_get_dquots(struct inode *inode)
80653873638SJan Kara {
80753873638SJan Kara 	return REISERFS_I(inode)->i_dquot;
80853873638SJan Kara }
8091da177e4SLinus Torvalds #endif
8101da177e4SLinus Torvalds 
811ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations reiserfs_sops = {
8121da177e4SLinus Torvalds 	.alloc_inode = reiserfs_alloc_inode,
813a5a8cbeaSAl Viro 	.free_inode = reiserfs_free_inode,
8141da177e4SLinus Torvalds 	.write_inode = reiserfs_write_inode,
8151da177e4SLinus Torvalds 	.dirty_inode = reiserfs_dirty_inode,
816845a2cc0SAl Viro 	.evict_inode = reiserfs_evict_inode,
8171da177e4SLinus Torvalds 	.put_super = reiserfs_put_super,
8181da177e4SLinus Torvalds 	.sync_fs = reiserfs_sync_fs,
819c4be0c1dSTakashi Sato 	.freeze_fs = reiserfs_freeze,
820c4be0c1dSTakashi Sato 	.unfreeze_fs = reiserfs_unfreeze,
8211da177e4SLinus Torvalds 	.statfs = reiserfs_statfs,
8221da177e4SLinus Torvalds 	.remount_fs = reiserfs_remount,
823c3aa0776SJan Kara 	.show_options = reiserfs_show_options,
8241da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
8251da177e4SLinus Torvalds 	.quota_read = reiserfs_quota_read,
8261da177e4SLinus Torvalds 	.quota_write = reiserfs_quota_write,
82753873638SJan Kara 	.get_dquots = reiserfs_get_dquots,
8281da177e4SLinus Torvalds #endif
8291da177e4SLinus Torvalds };
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
8321da177e4SLinus Torvalds #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds static int reiserfs_write_dquot(struct dquot *);
8351da177e4SLinus Torvalds static int reiserfs_acquire_dquot(struct dquot *);
8361da177e4SLinus Torvalds static int reiserfs_release_dquot(struct dquot *);
8371da177e4SLinus Torvalds static int reiserfs_mark_dquot_dirty(struct dquot *);
8381da177e4SLinus Torvalds static int reiserfs_write_info(struct super_block *, int);
8398c54ca9cSAl Viro static int reiserfs_quota_on(struct super_block *, int, int, const struct path *);
8401da177e4SLinus Torvalds 
84161e225dcSAlexey Dobriyan static const struct dquot_operations reiserfs_quota_operations = {
8421da177e4SLinus Torvalds 	.write_dquot = reiserfs_write_dquot,
8431da177e4SLinus Torvalds 	.acquire_dquot = reiserfs_acquire_dquot,
8441da177e4SLinus Torvalds 	.release_dquot = reiserfs_release_dquot,
8451da177e4SLinus Torvalds 	.mark_dirty = reiserfs_mark_dquot_dirty,
8461da177e4SLinus Torvalds 	.write_info = reiserfs_write_info,
8474103003bSJan Kara 	.alloc_dquot	= dquot_alloc,
8484103003bSJan Kara 	.destroy_dquot	= dquot_destroy,
849be6257b2SJan Kara 	.get_next_id	= dquot_get_next_id,
8501da177e4SLinus Torvalds };
8511da177e4SLinus Torvalds 
8520d54b217SAlexey Dobriyan static const struct quotactl_ops reiserfs_qctl_operations = {
8531da177e4SLinus Torvalds 	.quota_on = reiserfs_quota_on,
85433eb928aSJan Kara 	.quota_off = reiserfs_quota_off,
855287a8095SChristoph Hellwig 	.quota_sync = dquot_quota_sync,
8560a240339SJan Kara 	.get_state = dquot_get_state,
857287a8095SChristoph Hellwig 	.set_info = dquot_set_dqinfo,
858287a8095SChristoph Hellwig 	.get_dqblk = dquot_get_dqblk,
859287a8095SChristoph Hellwig 	.set_dqblk = dquot_set_dqblk,
8601da177e4SLinus Torvalds };
8611da177e4SLinus Torvalds #endif
8621da177e4SLinus Torvalds 
86339655164SChristoph Hellwig static const struct export_operations reiserfs_export_ops = {
8641da177e4SLinus Torvalds 	.encode_fh = reiserfs_encode_fh,
865be55caf1SChristoph Hellwig 	.fh_to_dentry = reiserfs_fh_to_dentry,
866be55caf1SChristoph Hellwig 	.fh_to_parent = reiserfs_fh_to_parent,
8671da177e4SLinus Torvalds 	.get_parent = reiserfs_get_parent,
8681da177e4SLinus Torvalds };
8691da177e4SLinus Torvalds 
870098297b2SJeff Mahoney /*
871098297b2SJeff Mahoney  * this struct is used in reiserfs_getopt () for containing the value for
872098297b2SJeff Mahoney  * those mount options that have values rather than being toggles.
873098297b2SJeff Mahoney  */
8741da177e4SLinus Torvalds typedef struct {
8751da177e4SLinus Torvalds 	char *value;
876098297b2SJeff Mahoney 	/*
877098297b2SJeff Mahoney 	 * bitmask which is to set on mount_options bitmask
878098297b2SJeff Mahoney 	 * when this value is found, 0 is no bits are to be changed.
879098297b2SJeff Mahoney 	 */
880098297b2SJeff Mahoney 	int setmask;
881098297b2SJeff Mahoney 	/*
882098297b2SJeff Mahoney 	 * bitmask which is to clear on mount_options bitmask
883098297b2SJeff Mahoney 	 * when this value is found, 0 is no bits are to be changed.
884098297b2SJeff Mahoney 	 * This is applied BEFORE setmask
885098297b2SJeff Mahoney 	 */
886098297b2SJeff Mahoney 	int clrmask;
8871da177e4SLinus Torvalds } arg_desc_t;
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds /* Set this bit in arg_required to allow empty arguments */
8901da177e4SLinus Torvalds #define REISERFS_OPT_ALLOWEMPTY 31
8911da177e4SLinus Torvalds 
892098297b2SJeff Mahoney /*
893098297b2SJeff Mahoney  * this struct is used in reiserfs_getopt() for describing the
894098297b2SJeff Mahoney  * set of reiserfs mount options
895098297b2SJeff Mahoney  */
8961da177e4SLinus Torvalds typedef struct {
8971da177e4SLinus Torvalds 	char *option_name;
898098297b2SJeff Mahoney 
899098297b2SJeff Mahoney 	/* 0 if argument is not required, not 0 otherwise */
900098297b2SJeff Mahoney 	int arg_required;
901098297b2SJeff Mahoney 
902098297b2SJeff Mahoney 	/* list of values accepted by an option */
903098297b2SJeff Mahoney 	const arg_desc_t *values;
904098297b2SJeff Mahoney 
905098297b2SJeff Mahoney 	/*
906098297b2SJeff Mahoney 	 * bitmask which is to set on mount_options bitmask
907098297b2SJeff Mahoney 	 * when this value is found, 0 is no bits are to be changed.
908098297b2SJeff Mahoney 	 */
909098297b2SJeff Mahoney 	int setmask;
910098297b2SJeff Mahoney 
911098297b2SJeff Mahoney 	/*
912098297b2SJeff Mahoney 	 * bitmask which is to clear on mount_options bitmask
913098297b2SJeff Mahoney 	 * when this value is found, 0 is no bits are to be changed.
914098297b2SJeff Mahoney 	 * This is applied BEFORE setmask
915098297b2SJeff Mahoney 	 */
916098297b2SJeff Mahoney 	int clrmask;
9171da177e4SLinus Torvalds } opt_desc_t;
9181da177e4SLinus Torvalds 
9191da177e4SLinus Torvalds /* possible values for -o data= */
9201da177e4SLinus Torvalds static const arg_desc_t logging_mode[] = {
921bd4c625cSLinus Torvalds 	{"ordered", 1 << REISERFS_DATA_ORDERED,
922bd4c625cSLinus Torvalds 	 (1 << REISERFS_DATA_LOG | 1 << REISERFS_DATA_WRITEBACK)},
923bd4c625cSLinus Torvalds 	{"journal", 1 << REISERFS_DATA_LOG,
924bd4c625cSLinus Torvalds 	 (1 << REISERFS_DATA_ORDERED | 1 << REISERFS_DATA_WRITEBACK)},
925bd4c625cSLinus Torvalds 	{"writeback", 1 << REISERFS_DATA_WRITEBACK,
926bd4c625cSLinus Torvalds 	 (1 << REISERFS_DATA_ORDERED | 1 << REISERFS_DATA_LOG)},
927cd02b966SVladimir V. Saveliev 	{.value = NULL}
9281da177e4SLinus Torvalds };
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds /* possible values for -o barrier= */
9311da177e4SLinus Torvalds static const arg_desc_t barrier_mode[] = {
9321da177e4SLinus Torvalds 	{"none", 1 << REISERFS_BARRIER_NONE, 1 << REISERFS_BARRIER_FLUSH},
9331da177e4SLinus Torvalds 	{"flush", 1 << REISERFS_BARRIER_FLUSH, 1 << REISERFS_BARRIER_NONE},
934cd02b966SVladimir V. Saveliev 	{.value = NULL}
9351da177e4SLinus Torvalds };
9361da177e4SLinus Torvalds 
937098297b2SJeff Mahoney /*
938098297b2SJeff Mahoney  * possible values for "-o block-allocator=" and bits which are to be set in
939098297b2SJeff Mahoney  * s_mount_opt of reiserfs specific part of in-core super block
940098297b2SJeff Mahoney  */
9411da177e4SLinus Torvalds static const arg_desc_t balloc[] = {
9421da177e4SLinus Torvalds 	{"noborder", 1 << REISERFS_NO_BORDER, 0},
9431da177e4SLinus Torvalds 	{"border", 0, 1 << REISERFS_NO_BORDER},
9441da177e4SLinus Torvalds 	{"no_unhashed_relocation", 1 << REISERFS_NO_UNHASHED_RELOCATION, 0},
9451da177e4SLinus Torvalds 	{"hashed_relocation", 1 << REISERFS_HASHED_RELOCATION, 0},
9461da177e4SLinus Torvalds 	{"test4", 1 << REISERFS_TEST4, 0},
9471da177e4SLinus Torvalds 	{"notest4", 0, 1 << REISERFS_TEST4},
9481da177e4SLinus Torvalds 	{NULL, 0, 0}
9491da177e4SLinus Torvalds };
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds static const arg_desc_t tails[] = {
9521da177e4SLinus Torvalds 	{"on", 1 << REISERFS_LARGETAIL, 1 << REISERFS_SMALLTAIL},
9531da177e4SLinus Torvalds 	{"off", 0, (1 << REISERFS_LARGETAIL) | (1 << REISERFS_SMALLTAIL)},
9541da177e4SLinus Torvalds 	{"small", 1 << REISERFS_SMALLTAIL, 1 << REISERFS_LARGETAIL},
9551da177e4SLinus Torvalds 	{NULL, 0, 0}
9561da177e4SLinus Torvalds };
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds static const arg_desc_t error_actions[] = {
9591da177e4SLinus Torvalds 	{"panic", 1 << REISERFS_ERROR_PANIC,
9601da177e4SLinus Torvalds 	 (1 << REISERFS_ERROR_RO | 1 << REISERFS_ERROR_CONTINUE)},
9611da177e4SLinus Torvalds 	{"ro-remount", 1 << REISERFS_ERROR_RO,
9621da177e4SLinus Torvalds 	 (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_CONTINUE)},
9631da177e4SLinus Torvalds #ifdef REISERFS_JOURNAL_ERROR_ALLOWS_NO_LOG
9641da177e4SLinus Torvalds 	{"continue", 1 << REISERFS_ERROR_CONTINUE,
9651da177e4SLinus Torvalds 	 (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_RO)},
9661da177e4SLinus Torvalds #endif
9671da177e4SLinus Torvalds 	{NULL, 0, 0},
9681da177e4SLinus Torvalds };
9691da177e4SLinus Torvalds 
970098297b2SJeff Mahoney /*
971098297b2SJeff Mahoney  * proceed only one option from a list *cur - string containing of mount
972098297b2SJeff Mahoney  * options
973098297b2SJeff Mahoney  * opts - array of options which are accepted
974098297b2SJeff Mahoney  * opt_arg - if option is found and requires an argument and if it is specifed
975098297b2SJeff Mahoney  * in the input - pointer to the argument is stored here
976098297b2SJeff Mahoney  * bit_flags - if option requires to set a certain bit - it is set here
977098297b2SJeff Mahoney  * return -1 if unknown option is found, opt->arg_required otherwise
978098297b2SJeff Mahoney  */
reiserfs_getopt(struct super_block * s,char ** cur,opt_desc_t * opts,char ** opt_arg,unsigned long * bit_flags)979bd4c625cSLinus Torvalds static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
980bd4c625cSLinus Torvalds 			   char **opt_arg, unsigned long *bit_flags)
9811da177e4SLinus Torvalds {
9821da177e4SLinus Torvalds 	char *p;
983098297b2SJeff Mahoney 	/*
984098297b2SJeff Mahoney 	 * foo=bar,
985098297b2SJeff Mahoney 	 * ^   ^  ^
986098297b2SJeff Mahoney 	 * |   |  +-- option_end
987098297b2SJeff Mahoney 	 * |   +-- arg_start
988098297b2SJeff Mahoney 	 * +-- option_start
9891da177e4SLinus Torvalds 	 */
9901da177e4SLinus Torvalds 	const opt_desc_t *opt;
9911da177e4SLinus Torvalds 	const arg_desc_t *arg;
9921da177e4SLinus Torvalds 
9931da177e4SLinus Torvalds 	p = *cur;
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds 	/* assume argument cannot contain commas */
9961da177e4SLinus Torvalds 	*cur = strchr(p, ',');
9971da177e4SLinus Torvalds 	if (*cur) {
9981da177e4SLinus Torvalds 		*(*cur) = '\0';
9991da177e4SLinus Torvalds 		(*cur)++;
10001da177e4SLinus Torvalds 	}
10011da177e4SLinus Torvalds 
10021da177e4SLinus Torvalds 	if (!strncmp(p, "alloc=", 6)) {
1003098297b2SJeff Mahoney 		/*
1004098297b2SJeff Mahoney 		 * Ugly special case, probably we should redo options
1005098297b2SJeff Mahoney 		 * parser so that it can understand several arguments for
1006098297b2SJeff Mahoney 		 * some options, also so that it can fill several bitfields
1007098297b2SJeff Mahoney 		 * with option values.
1008098297b2SJeff Mahoney 		 */
10091da177e4SLinus Torvalds 		if (reiserfs_parse_alloc_options(s, p + 6)) {
10101da177e4SLinus Torvalds 			return -1;
10111da177e4SLinus Torvalds 		} else {
10121da177e4SLinus Torvalds 			return 0;
10131da177e4SLinus Torvalds 		}
10141da177e4SLinus Torvalds 	}
10151da177e4SLinus Torvalds 
10161da177e4SLinus Torvalds 	/* for every option in the list */
10171da177e4SLinus Torvalds 	for (opt = opts; opt->option_name; opt++) {
10181da177e4SLinus Torvalds 		if (!strncmp(p, opt->option_name, strlen(opt->option_name))) {
10191da177e4SLinus Torvalds 			if (bit_flags) {
1020bd4c625cSLinus Torvalds 				if (opt->clrmask ==
1021bd4c625cSLinus Torvalds 				    (1 << REISERFS_UNSUPPORTED_OPT))
102245b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6500",
102345b03d5eSJeff Mahoney 							 "%s not supported.\n",
1024bd4c625cSLinus Torvalds 							 p);
10251da177e4SLinus Torvalds 				else
10261da177e4SLinus Torvalds 					*bit_flags &= ~opt->clrmask;
1027bd4c625cSLinus Torvalds 				if (opt->setmask ==
1028bd4c625cSLinus Torvalds 				    (1 << REISERFS_UNSUPPORTED_OPT))
102945b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6501",
103045b03d5eSJeff Mahoney 							 "%s not supported.\n",
1031bd4c625cSLinus Torvalds 							 p);
10321da177e4SLinus Torvalds 				else
10331da177e4SLinus Torvalds 					*bit_flags |= opt->setmask;
10341da177e4SLinus Torvalds 			}
10351da177e4SLinus Torvalds 			break;
10361da177e4SLinus Torvalds 		}
10371da177e4SLinus Torvalds 	}
10381da177e4SLinus Torvalds 	if (!opt->option_name) {
103945b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6502",
104045b03d5eSJeff Mahoney 				 "unknown mount option \"%s\"", p);
10411da177e4SLinus Torvalds 		return -1;
10421da177e4SLinus Torvalds 	}
10431da177e4SLinus Torvalds 
10441da177e4SLinus Torvalds 	p += strlen(opt->option_name);
10451da177e4SLinus Torvalds 	switch (*p) {
10461da177e4SLinus Torvalds 	case '=':
10471da177e4SLinus Torvalds 		if (!opt->arg_required) {
104845b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6503",
104945b03d5eSJeff Mahoney 					 "the option \"%s\" does not "
105045b03d5eSJeff Mahoney 					 "require an argument\n",
10511da177e4SLinus Torvalds 					 opt->option_name);
10521da177e4SLinus Torvalds 			return -1;
10531da177e4SLinus Torvalds 		}
10541da177e4SLinus Torvalds 		break;
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 	case 0:
10571da177e4SLinus Torvalds 		if (opt->arg_required) {
105845b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6504",
105945b03d5eSJeff Mahoney 					 "the option \"%s\" requires an "
106045b03d5eSJeff Mahoney 					 "argument\n", opt->option_name);
10611da177e4SLinus Torvalds 			return -1;
10621da177e4SLinus Torvalds 		}
10631da177e4SLinus Torvalds 		break;
10641da177e4SLinus Torvalds 	default:
106545b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6505",
106645b03d5eSJeff Mahoney 				 "head of option \"%s\" is only correct\n",
1067bd4c625cSLinus Torvalds 				 opt->option_name);
10681da177e4SLinus Torvalds 		return -1;
10691da177e4SLinus Torvalds 	}
10701da177e4SLinus Torvalds 
1071098297b2SJeff Mahoney 	/*
1072098297b2SJeff Mahoney 	 * move to the argument, or to next option if argument is not
1073098297b2SJeff Mahoney 	 * required
1074098297b2SJeff Mahoney 	 */
10751da177e4SLinus Torvalds 	p++;
10761da177e4SLinus Torvalds 
1077bd4c625cSLinus Torvalds 	if (opt->arg_required
1078bd4c625cSLinus Torvalds 	    && !(opt->arg_required & (1 << REISERFS_OPT_ALLOWEMPTY))
1079bd4c625cSLinus Torvalds 	    && !strlen(p)) {
10801da177e4SLinus Torvalds 		/* this catches "option=," if not allowed */
108145b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6506",
108245b03d5eSJeff Mahoney 				 "empty argument for \"%s\"\n",
1083bd4c625cSLinus Torvalds 				 opt->option_name);
10841da177e4SLinus Torvalds 		return -1;
10851da177e4SLinus Torvalds 	}
10861da177e4SLinus Torvalds 
10871da177e4SLinus Torvalds 	if (!opt->values) {
10881da177e4SLinus Torvalds 		/* *=NULLopt_arg contains pointer to argument */
10891da177e4SLinus Torvalds 		*opt_arg = p;
10901da177e4SLinus Torvalds 		return opt->arg_required & ~(1 << REISERFS_OPT_ALLOWEMPTY);
10911da177e4SLinus Torvalds 	}
10921da177e4SLinus Torvalds 
10931da177e4SLinus Torvalds 	/* values possible for this option are listed in opt->values */
10941da177e4SLinus Torvalds 	for (arg = opt->values; arg->value; arg++) {
10951da177e4SLinus Torvalds 		if (!strcmp(p, arg->value)) {
10961da177e4SLinus Torvalds 			if (bit_flags) {
10971da177e4SLinus Torvalds 				*bit_flags &= ~arg->clrmask;
10981da177e4SLinus Torvalds 				*bit_flags |= arg->setmask;
10991da177e4SLinus Torvalds 			}
11001da177e4SLinus Torvalds 			return opt->arg_required;
11011da177e4SLinus Torvalds 		}
11021da177e4SLinus Torvalds 	}
11031da177e4SLinus Torvalds 
110445b03d5eSJeff Mahoney 	reiserfs_warning(s, "super-6506",
110545b03d5eSJeff Mahoney 			 "bad value \"%s\" for option \"%s\"\n", p,
1106bd4c625cSLinus Torvalds 			 opt->option_name);
11071da177e4SLinus Torvalds 	return -1;
11081da177e4SLinus Torvalds }
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds /* returns 0 if something is wrong in option string, 1 - otherwise */
reiserfs_parse_options(struct super_block * s,char * options,unsigned long * mount_options,unsigned long * blocks,char ** jdev_name,unsigned int * commit_max_age,char ** qf_names,unsigned int * qfmt)1111098297b2SJeff Mahoney static int reiserfs_parse_options(struct super_block *s,
1112098297b2SJeff Mahoney 
1113098297b2SJeff Mahoney 				  /* string given via mount's -o */
1114098297b2SJeff Mahoney 				  char *options,
1115098297b2SJeff Mahoney 
1116098297b2SJeff Mahoney 				  /*
1117098297b2SJeff Mahoney 				   * after the parsing phase, contains the
1118098297b2SJeff Mahoney 				   * collection of bitflags defining what
1119098297b2SJeff Mahoney 				   * mount options were selected.
1120098297b2SJeff Mahoney 				   */
11211da177e4SLinus Torvalds 				  unsigned long *mount_options,
1122098297b2SJeff Mahoney 
1123098297b2SJeff Mahoney 				  /* strtol-ed from NNN of resize=NNN */
1124098297b2SJeff Mahoney 				  unsigned long *blocks,
11251da177e4SLinus Torvalds 				  char **jdev_name,
112600b44197SJan Kara 				  unsigned int *commit_max_age,
112700b44197SJan Kara 				  char **qf_names,
112800b44197SJan Kara 				  unsigned int *qfmt)
11291da177e4SLinus Torvalds {
11301da177e4SLinus Torvalds 	int c;
11311da177e4SLinus Torvalds 	char *arg = NULL;
11321da177e4SLinus Torvalds 	char *pos;
11331da177e4SLinus Torvalds 	opt_desc_t opts[] = {
1134098297b2SJeff Mahoney 		/*
1135098297b2SJeff Mahoney 		 * Compatibility stuff, so that -o notail for old
1136098297b2SJeff Mahoney 		 * setups still work
1137098297b2SJeff Mahoney 		 */
11381da177e4SLinus Torvalds 		{"tails",.arg_required = 't',.values = tails},
1139bd4c625cSLinus Torvalds 		{"notail",.clrmask =
1140bd4c625cSLinus Torvalds 		 (1 << REISERFS_LARGETAIL) | (1 << REISERFS_SMALLTAIL)},
11411da177e4SLinus Torvalds 		{"conv",.setmask = 1 << REISERFS_CONVERT},
11421da177e4SLinus Torvalds 		{"attrs",.setmask = 1 << REISERFS_ATTRS},
11431da177e4SLinus Torvalds 		{"noattrs",.clrmask = 1 << REISERFS_ATTRS},
114473422811SJeff Mahoney 		{"expose_privroot", .setmask = 1 << REISERFS_EXPOSE_PRIVROOT},
11451da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_FS_XATTR
11461da177e4SLinus Torvalds 		{"user_xattr",.setmask = 1 << REISERFS_XATTRS_USER},
11471da177e4SLinus Torvalds 		{"nouser_xattr",.clrmask = 1 << REISERFS_XATTRS_USER},
11481da177e4SLinus Torvalds #else
11491da177e4SLinus Torvalds 		{"user_xattr",.setmask = 1 << REISERFS_UNSUPPORTED_OPT},
11501da177e4SLinus Torvalds 		{"nouser_xattr",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT},
11511da177e4SLinus Torvalds #endif
11521da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_FS_POSIX_ACL
11531da177e4SLinus Torvalds 		{"acl",.setmask = 1 << REISERFS_POSIXACL},
11541da177e4SLinus Torvalds 		{"noacl",.clrmask = 1 << REISERFS_POSIXACL},
11551da177e4SLinus Torvalds #else
11561da177e4SLinus Torvalds 		{"acl",.setmask = 1 << REISERFS_UNSUPPORTED_OPT},
11571da177e4SLinus Torvalds 		{"noacl",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT},
11581da177e4SLinus Torvalds #endif
1159cd02b966SVladimir V. Saveliev 		{.option_name = "nolog"},
11601da177e4SLinus Torvalds 		{"replayonly",.setmask = 1 << REPLAYONLY},
11611da177e4SLinus Torvalds 		{"block-allocator",.arg_required = 'a',.values = balloc},
11621da177e4SLinus Torvalds 		{"data",.arg_required = 'd',.values = logging_mode},
11631da177e4SLinus Torvalds 		{"barrier",.arg_required = 'b',.values = barrier_mode},
11641da177e4SLinus Torvalds 		{"resize",.arg_required = 'r',.values = NULL},
11651da177e4SLinus Torvalds 		{"jdev",.arg_required = 'j',.values = NULL},
11661da177e4SLinus Torvalds 		{"nolargeio",.arg_required = 'w',.values = NULL},
11671da177e4SLinus Torvalds 		{"commit",.arg_required = 'c',.values = NULL},
1168c3aa0776SJan Kara 		{"usrquota",.setmask = 1 << REISERFS_USRQUOTA},
1169c3aa0776SJan Kara 		{"grpquota",.setmask = 1 << REISERFS_GRPQUOTA},
1170c3aa0776SJan Kara 		{"noquota",.clrmask = 1 << REISERFS_USRQUOTA | 1 << REISERFS_GRPQUOTA},
11711da177e4SLinus Torvalds 		{"errors",.arg_required = 'e',.values = error_actions},
1172bd4c625cSLinus Torvalds 		{"usrjquota",.arg_required =
1173bd4c625cSLinus Torvalds 		 'u' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL},
1174bd4c625cSLinus Torvalds 		{"grpjquota",.arg_required =
1175bd4c625cSLinus Torvalds 		 'g' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL},
11761da177e4SLinus Torvalds 		{"jqfmt",.arg_required = 'f',.values = NULL},
1177cd02b966SVladimir V. Saveliev 		{.option_name = NULL}
11781da177e4SLinus Torvalds 	};
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 	*blocks = 0;
11811da177e4SLinus Torvalds 	if (!options || !*options)
1182098297b2SJeff Mahoney 		/*
1183098297b2SJeff Mahoney 		 * use default configuration: create tails, journaling on, no
1184098297b2SJeff Mahoney 		 * conversion to newest format
1185098297b2SJeff Mahoney 		 */
11861da177e4SLinus Torvalds 		return 1;
11871da177e4SLinus Torvalds 
11881da177e4SLinus Torvalds 	for (pos = options; pos;) {
11891da177e4SLinus Torvalds 		c = reiserfs_getopt(s, &pos, opts, &arg, mount_options);
11901da177e4SLinus Torvalds 		if (c == -1)
11911da177e4SLinus Torvalds 			/* wrong option is given */
11921da177e4SLinus Torvalds 			return 0;
11931da177e4SLinus Torvalds 
11941da177e4SLinus Torvalds 		if (c == 'r') {
11951da177e4SLinus Torvalds 			char *p;
11961da177e4SLinus Torvalds 
11971da177e4SLinus Torvalds 			p = NULL;
11989a3bb301SPaolo 'Blaisorblade' Giarrusso 			/* "resize=NNN" or "resize=auto" */
11999a3bb301SPaolo 'Blaisorblade' Giarrusso 
12009a3bb301SPaolo 'Blaisorblade' Giarrusso 			if (!strcmp(arg, "auto")) {
12019a3bb301SPaolo 'Blaisorblade' Giarrusso 				/* From JFS code, to auto-get the size. */
12022ffae493SChristoph Hellwig 				*blocks = sb_bdev_nr_blocks(s);
12039a3bb301SPaolo 'Blaisorblade' Giarrusso 			} else {
12041da177e4SLinus Torvalds 				*blocks = simple_strtoul(arg, &p, 0);
12051da177e4SLinus Torvalds 				if (*p != '\0') {
12061da177e4SLinus Torvalds 					/* NNN does not look like a number */
120745b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6507",
120845b03d5eSJeff Mahoney 							 "bad value %s for "
120945b03d5eSJeff Mahoney 							 "-oresize\n", arg);
12101da177e4SLinus Torvalds 					return 0;
12111da177e4SLinus Torvalds 				}
12121da177e4SLinus Torvalds 			}
12139a3bb301SPaolo 'Blaisorblade' Giarrusso 		}
12141da177e4SLinus Torvalds 
12151da177e4SLinus Torvalds 		if (c == 'c') {
12161da177e4SLinus Torvalds 			char *p = NULL;
12171da177e4SLinus Torvalds 			unsigned long val = simple_strtoul(arg, &p, 0);
12181da177e4SLinus Torvalds 			/* commit=NNN (time in seconds) */
12191da177e4SLinus Torvalds 			if (*p != '\0' || val >= (unsigned int)-1) {
122045b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-6508",
122145b03d5eSJeff Mahoney 						 "bad value %s for -ocommit\n",
1222bd4c625cSLinus Torvalds 						 arg);
12239a3bb301SPaolo 'Blaisorblade' Giarrusso 				return 0;
12241da177e4SLinus Torvalds 			}
12251da177e4SLinus Torvalds 			*commit_max_age = (unsigned int)val;
12261da177e4SLinus Torvalds 		}
12271da177e4SLinus Torvalds 
12281da177e4SLinus Torvalds 		if (c == 'w') {
122945b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6509", "nolargeio option "
123045b03d5eSJeff Mahoney 					 "is no longer supported");
12311da177e4SLinus Torvalds 			return 0;
12321da177e4SLinus Torvalds 		}
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds 		if (c == 'j') {
12351da177e4SLinus Torvalds 			if (arg && *arg && jdev_name) {
1236098297b2SJeff Mahoney 				/* Hm, already assigned? */
1237098297b2SJeff Mahoney 				if (*jdev_name) {
123845b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6510",
123945b03d5eSJeff Mahoney 							 "journal device was "
124045b03d5eSJeff Mahoney 							 "already specified to "
124145b03d5eSJeff Mahoney 							 "be %s", *jdev_name);
12421da177e4SLinus Torvalds 					return 0;
12431da177e4SLinus Torvalds 				}
12441da177e4SLinus Torvalds 				*jdev_name = arg;
12451da177e4SLinus Torvalds 			}
12461da177e4SLinus Torvalds 		}
12471da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
12481da177e4SLinus Torvalds 		if (c == 'u' || c == 'g') {
12491da177e4SLinus Torvalds 			int qtype = c == 'u' ? USRQUOTA : GRPQUOTA;
12501da177e4SLinus Torvalds 
12516929f891SJan Kara 			if (sb_any_quota_loaded(s) &&
125200b44197SJan Kara 			    (!*arg != !REISERFS_SB(s)->s_qf_names[qtype])) {
125345b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-6511",
125445b03d5eSJeff Mahoney 						 "cannot change journaled "
125545b03d5eSJeff Mahoney 						 "quota options when quota "
125645b03d5eSJeff Mahoney 						 "turned on.");
12571da177e4SLinus Torvalds 				return 0;
12581da177e4SLinus Torvalds 			}
1259e9d4709fSJan Kara 			if (qf_names[qtype] !=
1260e9d4709fSJan Kara 			    REISERFS_SB(s)->s_qf_names[qtype])
1261e9d4709fSJan Kara 				kfree(qf_names[qtype]);
1262e9d4709fSJan Kara 			qf_names[qtype] = NULL;
12631da177e4SLinus Torvalds 			if (*arg) {	/* Some filename specified? */
1264bd4c625cSLinus Torvalds 				if (REISERFS_SB(s)->s_qf_names[qtype]
1265bd4c625cSLinus Torvalds 				    && strcmp(REISERFS_SB(s)->s_qf_names[qtype],
1266bd4c625cSLinus Torvalds 					      arg)) {
126745b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6512",
126845b03d5eSJeff Mahoney 							 "%s quota file "
126945b03d5eSJeff Mahoney 							 "already specified.",
1270bd4c625cSLinus Torvalds 							 QTYPE2NAME(qtype));
12711da177e4SLinus Torvalds 					return 0;
12721da177e4SLinus Torvalds 				}
12731da177e4SLinus Torvalds 				if (strchr(arg, '/')) {
127445b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6513",
127545b03d5eSJeff Mahoney 							 "quotafile must be "
127645b03d5eSJeff Mahoney 							 "on filesystem root.");
12771da177e4SLinus Torvalds 					return 0;
12781da177e4SLinus Torvalds 				}
1279af591ad8SIonut-Gabriel Radu 				qf_names[qtype] = kstrdup(arg, GFP_KERNEL);
128000b44197SJan Kara 				if (!qf_names[qtype]) {
128145b03d5eSJeff Mahoney 					reiserfs_warning(s, "reiserfs-2502",
128245b03d5eSJeff Mahoney 							 "not enough memory "
128345b03d5eSJeff Mahoney 							 "for storing "
128445b03d5eSJeff Mahoney 							 "quotafile name.");
12851da177e4SLinus Torvalds 					return 0;
12861da177e4SLinus Torvalds 				}
1287c3aa0776SJan Kara 				if (qtype == USRQUOTA)
1288c3aa0776SJan Kara 					*mount_options |= 1 << REISERFS_USRQUOTA;
1289c3aa0776SJan Kara 				else
1290c3aa0776SJan Kara 					*mount_options |= 1 << REISERFS_GRPQUOTA;
1291bd4c625cSLinus Torvalds 			} else {
1292c3aa0776SJan Kara 				if (qtype == USRQUOTA)
1293c3aa0776SJan Kara 					*mount_options &= ~(1 << REISERFS_USRQUOTA);
1294c3aa0776SJan Kara 				else
1295c3aa0776SJan Kara 					*mount_options &= ~(1 << REISERFS_GRPQUOTA);
12961da177e4SLinus Torvalds 			}
12971da177e4SLinus Torvalds 		}
12981da177e4SLinus Torvalds 		if (c == 'f') {
12991da177e4SLinus Torvalds 			if (!strcmp(arg, "vfsold"))
130000b44197SJan Kara 				*qfmt = QFMT_VFS_OLD;
13011da177e4SLinus Torvalds 			else if (!strcmp(arg, "vfsv0"))
130200b44197SJan Kara 				*qfmt = QFMT_VFS_V0;
13031da177e4SLinus Torvalds 			else {
130445b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-6514",
130545b03d5eSJeff Mahoney 						 "unknown quota format "
130645b03d5eSJeff Mahoney 						 "specified.");
13071da177e4SLinus Torvalds 				return 0;
13081da177e4SLinus Torvalds 			}
13096929f891SJan Kara 			if (sb_any_quota_loaded(s) &&
131000b44197SJan Kara 			    *qfmt != REISERFS_SB(s)->s_jquota_fmt) {
131145b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-6515",
131245b03d5eSJeff Mahoney 						 "cannot change journaled "
131345b03d5eSJeff Mahoney 						 "quota options when quota "
131445b03d5eSJeff Mahoney 						 "turned on.");
131500b44197SJan Kara 				return 0;
131600b44197SJan Kara 			}
13171da177e4SLinus Torvalds 		}
13181da177e4SLinus Torvalds #else
13191da177e4SLinus Torvalds 		if (c == 'u' || c == 'g' || c == 'f') {
132045b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2503", "journaled "
132145b03d5eSJeff Mahoney 					 "quota options not supported.");
13221da177e4SLinus Torvalds 			return 0;
13231da177e4SLinus Torvalds 		}
13241da177e4SLinus Torvalds #endif
13251da177e4SLinus Torvalds 	}
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
132800b44197SJan Kara 	if (!REISERFS_SB(s)->s_jquota_fmt && !*qfmt
132900b44197SJan Kara 	    && (qf_names[USRQUOTA] || qf_names[GRPQUOTA])) {
133045b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6515",
133145b03d5eSJeff Mahoney 				 "journaled quota format not specified.");
13321da177e4SLinus Torvalds 		return 0;
13331da177e4SLinus Torvalds 	}
1334c3aa0776SJan Kara 	if ((!(*mount_options & (1 << REISERFS_USRQUOTA)) &&
1335c3aa0776SJan Kara 	       sb_has_quota_loaded(s, USRQUOTA)) ||
1336c3aa0776SJan Kara 	    (!(*mount_options & (1 << REISERFS_GRPQUOTA)) &&
1337c3aa0776SJan Kara 	       sb_has_quota_loaded(s, GRPQUOTA))) {
133845b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6516", "quota options must "
133945b03d5eSJeff Mahoney 				 "be present when quota is turned on.");
1340556a2a45SJan Kara 		return 0;
1341556a2a45SJan Kara 	}
13421da177e4SLinus Torvalds #endif
1343556a2a45SJan Kara 
13441da177e4SLinus Torvalds 	return 1;
13451da177e4SLinus Torvalds }
13461da177e4SLinus Torvalds 
switch_data_mode(struct super_block * s,unsigned long mode)1347bd4c625cSLinus Torvalds static void switch_data_mode(struct super_block *s, unsigned long mode)
1348bd4c625cSLinus Torvalds {
13491da177e4SLinus Torvalds 	REISERFS_SB(s)->s_mount_opt &= ~((1 << REISERFS_DATA_LOG) |
13501da177e4SLinus Torvalds 					 (1 << REISERFS_DATA_ORDERED) |
13511da177e4SLinus Torvalds 					 (1 << REISERFS_DATA_WRITEBACK));
13521da177e4SLinus Torvalds 	REISERFS_SB(s)->s_mount_opt |= (1 << mode);
13531da177e4SLinus Torvalds }
13541da177e4SLinus Torvalds 
handle_data_mode(struct super_block * s,unsigned long mount_options)13551da177e4SLinus Torvalds static void handle_data_mode(struct super_block *s, unsigned long mount_options)
13561da177e4SLinus Torvalds {
13571da177e4SLinus Torvalds 	if (mount_options & (1 << REISERFS_DATA_LOG)) {
13581da177e4SLinus Torvalds 		if (!reiserfs_data_log(s)) {
13591da177e4SLinus Torvalds 			switch_data_mode(s, REISERFS_DATA_LOG);
13601da177e4SLinus Torvalds 			reiserfs_info(s, "switching to journaled data mode\n");
13611da177e4SLinus Torvalds 		}
13621da177e4SLinus Torvalds 	} else if (mount_options & (1 << REISERFS_DATA_ORDERED)) {
13631da177e4SLinus Torvalds 		if (!reiserfs_data_ordered(s)) {
13641da177e4SLinus Torvalds 			switch_data_mode(s, REISERFS_DATA_ORDERED);
13651da177e4SLinus Torvalds 			reiserfs_info(s, "switching to ordered data mode\n");
13661da177e4SLinus Torvalds 		}
13671da177e4SLinus Torvalds 	} else if (mount_options & (1 << REISERFS_DATA_WRITEBACK)) {
13681da177e4SLinus Torvalds 		if (!reiserfs_data_writeback(s)) {
13691da177e4SLinus Torvalds 			switch_data_mode(s, REISERFS_DATA_WRITEBACK);
13701da177e4SLinus Torvalds 			reiserfs_info(s, "switching to writeback data mode\n");
13711da177e4SLinus Torvalds 		}
13721da177e4SLinus Torvalds 	}
13731da177e4SLinus Torvalds }
13741da177e4SLinus Torvalds 
handle_barrier_mode(struct super_block * s,unsigned long bits)1375bd4c625cSLinus Torvalds static void handle_barrier_mode(struct super_block *s, unsigned long bits)
1376bd4c625cSLinus Torvalds {
13771da177e4SLinus Torvalds 	int flush = (1 << REISERFS_BARRIER_FLUSH);
13781da177e4SLinus Torvalds 	int none = (1 << REISERFS_BARRIER_NONE);
13791da177e4SLinus Torvalds 	int all_barrier = flush | none;
13801da177e4SLinus Torvalds 
13811da177e4SLinus Torvalds 	if (bits & all_barrier) {
13821da177e4SLinus Torvalds 		REISERFS_SB(s)->s_mount_opt &= ~all_barrier;
13831da177e4SLinus Torvalds 		if (bits & flush) {
13841da177e4SLinus Torvalds 			REISERFS_SB(s)->s_mount_opt |= flush;
13851da177e4SLinus Torvalds 			printk("reiserfs: enabling write barrier flush mode\n");
13861da177e4SLinus Torvalds 		} else if (bits & none) {
13871da177e4SLinus Torvalds 			REISERFS_SB(s)->s_mount_opt |= none;
13881da177e4SLinus Torvalds 			printk("reiserfs: write barriers turned off\n");
13891da177e4SLinus Torvalds 		}
13901da177e4SLinus Torvalds 	}
13911da177e4SLinus Torvalds }
13921da177e4SLinus Torvalds 
handle_attrs(struct super_block * s)13931da177e4SLinus Torvalds static void handle_attrs(struct super_block *s)
13941da177e4SLinus Torvalds {
1395c60e81eeSAndrew Morton 	struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
13961da177e4SLinus Torvalds 
13971da177e4SLinus Torvalds 	if (reiserfs_attrs(s)) {
13981da177e4SLinus Torvalds 		if (old_format_only(s)) {
139945b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6517", "cannot support "
140045b03d5eSJeff Mahoney 					 "attributes on 3.5.x disk format");
14011da177e4SLinus Torvalds 			REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
14021da177e4SLinus Torvalds 			return;
14031da177e4SLinus Torvalds 		}
14041da177e4SLinus Torvalds 		if (!(le32_to_cpu(rs->s_flags) & reiserfs_attrs_cleared)) {
140545b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6518", "cannot support "
140645b03d5eSJeff Mahoney 					 "attributes until flag is set in "
140745b03d5eSJeff Mahoney 					 "super-block");
14081da177e4SLinus Torvalds 			REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
14091da177e4SLinus Torvalds 		}
14101da177e4SLinus Torvalds 	}
14111da177e4SLinus Torvalds }
14121da177e4SLinus Torvalds 
141300b44197SJan Kara #ifdef CONFIG_QUOTA
handle_quota_files(struct super_block * s,char ** qf_names,unsigned int * qfmt)141400b44197SJan Kara static void handle_quota_files(struct super_block *s, char **qf_names,
141500b44197SJan Kara 			       unsigned int *qfmt)
141600b44197SJan Kara {
141700b44197SJan Kara 	int i;
141800b44197SJan Kara 
1419aca60617SJan Kara 	for (i = 0; i < REISERFS_MAXQUOTAS; i++) {
142000b44197SJan Kara 		if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i])
142100b44197SJan Kara 			kfree(REISERFS_SB(s)->s_qf_names[i]);
142200b44197SJan Kara 		REISERFS_SB(s)->s_qf_names[i] = qf_names[i];
142300b44197SJan Kara 	}
1424a06d789bSJan Kara 	if (*qfmt)
142500b44197SJan Kara 		REISERFS_SB(s)->s_jquota_fmt = *qfmt;
142600b44197SJan Kara }
142700b44197SJan Kara #endif
142800b44197SJan Kara 
reiserfs_remount(struct super_block * s,int * mount_flags,char * arg)14291da177e4SLinus Torvalds static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
14301da177e4SLinus Torvalds {
14311da177e4SLinus Torvalds 	struct reiserfs_super_block *rs;
14321da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
14331da177e4SLinus Torvalds 	unsigned long blocks;
14341da177e4SLinus Torvalds 	unsigned long mount_options = REISERFS_SB(s)->s_mount_opt;
14351da177e4SLinus Torvalds 	unsigned long safe_mask = 0;
14361da177e4SLinus Torvalds 	unsigned int commit_max_age = (unsigned int)-1;
14371da177e4SLinus Torvalds 	struct reiserfs_journal *journal = SB_JOURNAL(s);
14381da177e4SLinus Torvalds 	int err;
1439aca60617SJan Kara 	char *qf_names[REISERFS_MAXQUOTAS];
144000b44197SJan Kara 	unsigned int qfmt = 0;
14411da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
14421da177e4SLinus Torvalds 	int i;
14438ebc4232SFrederic Weisbecker #endif
144400b44197SJan Kara 
144502b9984dSTheodore Ts'o 	sync_filesystem(s);
14468ebc4232SFrederic Weisbecker 	reiserfs_write_lock(s);
14478ebc4232SFrederic Weisbecker 
14488ebc4232SFrederic Weisbecker #ifdef CONFIG_QUOTA
144900b44197SJan Kara 	memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names));
14501da177e4SLinus Torvalds #endif
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds 	rs = SB_DISK_SUPER_BLOCK(s);
14531da177e4SLinus Torvalds 
1454bd4c625cSLinus Torvalds 	if (!reiserfs_parse_options
145500b44197SJan Kara 	    (s, arg, &mount_options, &blocks, NULL, &commit_max_age,
145600b44197SJan Kara 	    qf_names, &qfmt)) {
14571da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
1458aca60617SJan Kara 		for (i = 0; i < REISERFS_MAXQUOTAS; i++)
145900b44197SJan Kara 			if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i])
146000b44197SJan Kara 				kfree(qf_names[i]);
14611da177e4SLinus Torvalds #endif
1462cdf6ccc8SMiklos Szeredi 		err = -EINVAL;
14634c05141dSJeff Mahoney 		goto out_err_unlock;
14641da177e4SLinus Torvalds 	}
146500b44197SJan Kara #ifdef CONFIG_QUOTA
146600b44197SJan Kara 	handle_quota_files(s, qf_names, &qfmt);
146700b44197SJan Kara #endif
14681da177e4SLinus Torvalds 
14691da177e4SLinus Torvalds 	handle_attrs(s);
14701da177e4SLinus Torvalds 
14711da177e4SLinus Torvalds 	/* Add options that are safe here */
14721da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_SMALLTAIL;
14731da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_LARGETAIL;
14741da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_NO_BORDER;
14751da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_NO_UNHASHED_RELOCATION;
14761da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_HASHED_RELOCATION;
14771da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_TEST4;
14781da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_ATTRS;
14791da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_XATTRS_USER;
14801da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_POSIXACL;
14811da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
14821da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_BARRIER_NONE;
14831da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_ERROR_RO;
14841da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_ERROR_CONTINUE;
14851da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_ERROR_PANIC;
1486c3aa0776SJan Kara 	safe_mask |= 1 << REISERFS_USRQUOTA;
1487c3aa0776SJan Kara 	safe_mask |= 1 << REISERFS_GRPQUOTA;
14881da177e4SLinus Torvalds 
1489098297b2SJeff Mahoney 	/*
1490098297b2SJeff Mahoney 	 * Update the bitmask, taking care to keep
1491098297b2SJeff Mahoney 	 * the bits we're not allowed to change here
1492098297b2SJeff Mahoney 	 */
1493bd4c625cSLinus Torvalds 	REISERFS_SB(s)->s_mount_opt =
1494bd4c625cSLinus Torvalds 	    (REISERFS_SB(s)->
1495bd4c625cSLinus Torvalds 	     s_mount_opt & ~safe_mask) | (mount_options & safe_mask);
14961da177e4SLinus Torvalds 
14971da177e4SLinus Torvalds 	if (commit_max_age != 0 && commit_max_age != (unsigned int)-1) {
14981da177e4SLinus Torvalds 		journal->j_max_commit_age = commit_max_age;
14991da177e4SLinus Torvalds 		journal->j_max_trans_age = commit_max_age;
1500bd4c625cSLinus Torvalds 	} else if (commit_max_age == 0) {
15011da177e4SLinus Torvalds 		/* 0 means restore defaults. */
15021da177e4SLinus Torvalds 		journal->j_max_commit_age = journal->j_default_max_commit_age;
15031da177e4SLinus Torvalds 		journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE;
15041da177e4SLinus Torvalds 	}
15051da177e4SLinus Torvalds 
15061da177e4SLinus Torvalds 	if (blocks) {
1507cdf6ccc8SMiklos Szeredi 		err = reiserfs_resize(s, blocks);
1508cdf6ccc8SMiklos Szeredi 		if (err != 0)
15094c05141dSJeff Mahoney 			goto out_err_unlock;
15101da177e4SLinus Torvalds 	}
15111da177e4SLinus Torvalds 
15121751e8a6SLinus Torvalds 	if (*mount_flags & SB_RDONLY) {
15134c05141dSJeff Mahoney 		reiserfs_write_unlock(s);
15141da177e4SLinus Torvalds 		reiserfs_xattr_init(s, *mount_flags);
15151da177e4SLinus Torvalds 		/* remount read-only */
1516bc98a42cSDavid Howells 		if (sb_rdonly(s))
15171da177e4SLinus Torvalds 			/* it is read-only already */
15184c05141dSJeff Mahoney 			goto out_ok_unlocked;
1519c79d967dSChristoph Hellwig 
15200f0dd62fSChristoph Hellwig 		err = dquot_suspend(s, -1);
15210f0dd62fSChristoph Hellwig 		if (err < 0)
1522c79d967dSChristoph Hellwig 			goto out_err;
1523c79d967dSChristoph Hellwig 
15241da177e4SLinus Torvalds 		/* try to remount file system with read-only permissions */
1525bd4c625cSLinus Torvalds 		if (sb_umount_state(rs) == REISERFS_VALID_FS
1526bd4c625cSLinus Torvalds 		    || REISERFS_SB(s)->s_mount_state != REISERFS_VALID_FS) {
15274c05141dSJeff Mahoney 			goto out_ok_unlocked;
15281da177e4SLinus Torvalds 		}
15291da177e4SLinus Torvalds 
15304c05141dSJeff Mahoney 		reiserfs_write_lock(s);
15314c05141dSJeff Mahoney 
15321da177e4SLinus Torvalds 		err = journal_begin(&th, s, 10);
15331da177e4SLinus Torvalds 		if (err)
15344c05141dSJeff Mahoney 			goto out_err_unlock;
15351da177e4SLinus Torvalds 
15361da177e4SLinus Torvalds 		/* Mounting a rw partition read-only. */
15371da177e4SLinus Torvalds 		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
15381da177e4SLinus Torvalds 		set_sb_umount_state(rs, REISERFS_SB(s)->s_mount_state);
153909f1b80bSJeff Mahoney 		journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));
15401da177e4SLinus Torvalds 	} else {
15411da177e4SLinus Torvalds 		/* remount read-write */
1542bc98a42cSDavid Howells 		if (!sb_rdonly(s)) {
15434c05141dSJeff Mahoney 			reiserfs_write_unlock(s);
15441da177e4SLinus Torvalds 			reiserfs_xattr_init(s, *mount_flags);
15454c05141dSJeff Mahoney 			goto out_ok_unlocked;	/* We are read-write already */
15461da177e4SLinus Torvalds 		}
15471da177e4SLinus Torvalds 
1548cdf6ccc8SMiklos Szeredi 		if (reiserfs_is_journal_aborted(journal)) {
1549cdf6ccc8SMiklos Szeredi 			err = journal->j_errno;
15504c05141dSJeff Mahoney 			goto out_err_unlock;
1551cdf6ccc8SMiklos Szeredi 		}
15521da177e4SLinus Torvalds 
15531da177e4SLinus Torvalds 		handle_data_mode(s, mount_options);
15541da177e4SLinus Torvalds 		handle_barrier_mode(s, mount_options);
15551da177e4SLinus Torvalds 		REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
1556098297b2SJeff Mahoney 
1557098297b2SJeff Mahoney 		/* now it is safe to call journal_begin */
15581751e8a6SLinus Torvalds 		s->s_flags &= ~SB_RDONLY;
15591da177e4SLinus Torvalds 		err = journal_begin(&th, s, 10);
15601da177e4SLinus Torvalds 		if (err)
15614c05141dSJeff Mahoney 			goto out_err_unlock;
15621da177e4SLinus Torvalds 
15631da177e4SLinus Torvalds 		/* Mount a partition which is read-only, read-write */
15641da177e4SLinus Torvalds 		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
15651da177e4SLinus Torvalds 		REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
15661751e8a6SLinus Torvalds 		s->s_flags &= ~SB_RDONLY;
15671da177e4SLinus Torvalds 		set_sb_umount_state(rs, REISERFS_ERROR_FS);
1568702d21c6SJeff Mahoney 		if (!old_format_only(s))
1569702d21c6SJeff Mahoney 			set_sb_mnt_count(rs, sb_mnt_count(rs) + 1);
15701da177e4SLinus Torvalds 		/* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */
157109f1b80bSJeff Mahoney 		journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));
15721da177e4SLinus Torvalds 		REISERFS_SB(s)->s_mount_state = REISERFS_VALID_FS;
15731da177e4SLinus Torvalds 	}
15741da177e4SLinus Torvalds 	/* this will force a full flush of all journal lists */
15751da177e4SLinus Torvalds 	SB_JOURNAL(s)->j_must_wait = 1;
157658d85426SJeff Mahoney 	err = journal_end(&th);
15771da177e4SLinus Torvalds 	if (err)
15784c05141dSJeff Mahoney 		goto out_err_unlock;
15791da177e4SLinus Torvalds 
15803bb3e1fcSJan Kara 	reiserfs_write_unlock(s);
15811751e8a6SLinus Torvalds 	if (!(*mount_flags & SB_RDONLY)) {
15820f0dd62fSChristoph Hellwig 		dquot_resume(s, -1);
15833bb3e1fcSJan Kara 		reiserfs_write_lock(s);
15841da177e4SLinus Torvalds 		finish_unfinished(s);
15854c05141dSJeff Mahoney 		reiserfs_write_unlock(s);
15861da177e4SLinus Torvalds 		reiserfs_xattr_init(s, *mount_flags);
15871da177e4SLinus Torvalds 	}
15881da177e4SLinus Torvalds 
15894c05141dSJeff Mahoney out_ok_unlocked:
15901da177e4SLinus Torvalds 	return 0;
1591cdf6ccc8SMiklos Szeredi 
15924c05141dSJeff Mahoney out_err_unlock:
15933bb3e1fcSJan Kara 	reiserfs_write_unlock(s);
1594cdf6ccc8SMiklos Szeredi out_err:
1595cdf6ccc8SMiklos Szeredi 	return err;
15961da177e4SLinus Torvalds }
15971da177e4SLinus Torvalds 
read_super_block(struct super_block * s,int offset)15981da177e4SLinus Torvalds static int read_super_block(struct super_block *s, int offset)
15991da177e4SLinus Torvalds {
16001da177e4SLinus Torvalds 	struct buffer_head *bh;
16011da177e4SLinus Torvalds 	struct reiserfs_super_block *rs;
16021da177e4SLinus Torvalds 	int fs_blocksize;
16031da177e4SLinus Torvalds 
16041da177e4SLinus Torvalds 	bh = sb_bread(s, offset / s->s_blocksize);
16051da177e4SLinus Torvalds 	if (!bh) {
160645b03d5eSJeff Mahoney 		reiserfs_warning(s, "sh-2006",
16071da177e4SLinus Torvalds 				 "bread failed (dev %s, block %lu, size %lu)",
16082ccdc413SAl Viro 				 s->s_id, offset / s->s_blocksize,
1609bd4c625cSLinus Torvalds 				 s->s_blocksize);
16101da177e4SLinus Torvalds 		return 1;
16111da177e4SLinus Torvalds 	}
16121da177e4SLinus Torvalds 
16131da177e4SLinus Torvalds 	rs = (struct reiserfs_super_block *)bh->b_data;
16141da177e4SLinus Torvalds 	if (!is_any_reiserfs_magic_string(rs)) {
16151da177e4SLinus Torvalds 		brelse(bh);
16161da177e4SLinus Torvalds 		return 1;
16171da177e4SLinus Torvalds 	}
1618098297b2SJeff Mahoney 	/*
1619098297b2SJeff Mahoney 	 * ok, reiserfs signature (old or new) found in at the given offset
1620098297b2SJeff Mahoney 	 */
16211da177e4SLinus Torvalds 	fs_blocksize = sb_blocksize(rs);
16221da177e4SLinus Torvalds 	brelse(bh);
16231da177e4SLinus Torvalds 	sb_set_blocksize(s, fs_blocksize);
16241da177e4SLinus Torvalds 
16251da177e4SLinus Torvalds 	bh = sb_bread(s, offset / s->s_blocksize);
16261da177e4SLinus Torvalds 	if (!bh) {
162745b03d5eSJeff Mahoney 		reiserfs_warning(s, "sh-2007",
162845b03d5eSJeff Mahoney 				 "bread failed (dev %s, block %lu, size %lu)",
16292ccdc413SAl Viro 				 s->s_id, offset / s->s_blocksize,
1630bd4c625cSLinus Torvalds 				 s->s_blocksize);
16311da177e4SLinus Torvalds 		return 1;
16321da177e4SLinus Torvalds 	}
16331da177e4SLinus Torvalds 
16341da177e4SLinus Torvalds 	rs = (struct reiserfs_super_block *)bh->b_data;
16351da177e4SLinus Torvalds 	if (sb_blocksize(rs) != s->s_blocksize) {
163645b03d5eSJeff Mahoney 		reiserfs_warning(s, "sh-2011", "can't find a reiserfs "
163753872ed0SFabian Frederick 				 "filesystem on (dev %s, block %llu, size %lu)",
16382ccdc413SAl Viro 				 s->s_id,
1639bd4c625cSLinus Torvalds 				 (unsigned long long)bh->b_blocknr,
1640bd4c625cSLinus Torvalds 				 s->s_blocksize);
16411da177e4SLinus Torvalds 		brelse(bh);
16421da177e4SLinus Torvalds 		return 1;
16431da177e4SLinus Torvalds 	}
16441da177e4SLinus Torvalds 
16453e8962beSAl Viro 	if (rs->s_v1.s_root_block == cpu_to_le32(-1)) {
16461da177e4SLinus Torvalds 		brelse(bh);
164745b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6519", "Unfinished reiserfsck "
164845b03d5eSJeff Mahoney 				 "--rebuild-tree run detected. Please run\n"
164945b03d5eSJeff Mahoney 				 "reiserfsck --rebuild-tree and wait for a "
165045b03d5eSJeff Mahoney 				 "completion. If that fails\n"
16511da177e4SLinus Torvalds 				 "get newer reiserfsprogs package");
16521da177e4SLinus Torvalds 		return 1;
16531da177e4SLinus Torvalds 	}
16541da177e4SLinus Torvalds 
1655eb103a51SJan Kara 	reiserfs_warning(NULL, "", "reiserfs filesystem is deprecated and "
1656eb103a51SJan Kara 		"scheduled to be removed from the kernel in 2025");
16571da177e4SLinus Torvalds 	SB_BUFFER_WITH_SB(s) = bh;
16581da177e4SLinus Torvalds 	SB_DISK_SUPER_BLOCK(s) = rs;
16591da177e4SLinus Torvalds 
1660098297b2SJeff Mahoney 	/*
1661098297b2SJeff Mahoney 	 * magic is of non-standard journal filesystem, look at s_version to
1662098297b2SJeff Mahoney 	 * find which format is in use
1663098297b2SJeff Mahoney 	 */
16641da177e4SLinus Torvalds 	if (is_reiserfs_jr(rs)) {
16651da177e4SLinus Torvalds 		if (sb_version(rs) == REISERFS_VERSION_2)
16661d889d99SJeff Mahoney 			reiserfs_info(s, "found reiserfs format \"3.6\""
16671d889d99SJeff Mahoney 				      " with non-standard journal\n");
16681da177e4SLinus Torvalds 		else if (sb_version(rs) == REISERFS_VERSION_1)
16691d889d99SJeff Mahoney 			reiserfs_info(s, "found reiserfs format \"3.5\""
16701d889d99SJeff Mahoney 				      " with non-standard journal\n");
16711da177e4SLinus Torvalds 		else {
167245b03d5eSJeff Mahoney 			reiserfs_warning(s, "sh-2012", "found unknown "
167345b03d5eSJeff Mahoney 					 "format \"%u\" of reiserfs with "
167445b03d5eSJeff Mahoney 					 "non-standard magic", sb_version(rs));
16751da177e4SLinus Torvalds 			return 1;
16761da177e4SLinus Torvalds 		}
1677bd4c625cSLinus Torvalds 	} else
1678098297b2SJeff Mahoney 		/*
1679098297b2SJeff Mahoney 		 * s_version of standard format may contain incorrect
1680098297b2SJeff Mahoney 		 * information, so we just look at the magic string
1681098297b2SJeff Mahoney 		 */
1682bd4c625cSLinus Torvalds 		reiserfs_info(s,
1683bd4c625cSLinus Torvalds 			      "found reiserfs format \"%s\" with standard journal\n",
16841da177e4SLinus Torvalds 			      is_reiserfs_3_5(rs) ? "3.5" : "3.6");
16851da177e4SLinus Torvalds 
16861da177e4SLinus Torvalds 	s->s_op = &reiserfs_sops;
16871da177e4SLinus Torvalds 	s->s_export_op = &reiserfs_export_ops;
16881da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
16891da177e4SLinus Torvalds 	s->s_qcop = &reiserfs_qctl_operations;
16901da177e4SLinus Torvalds 	s->dq_op = &reiserfs_quota_operations;
169153873638SJan Kara 	s->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
16921da177e4SLinus Torvalds #endif
16931da177e4SLinus Torvalds 
1694098297b2SJeff Mahoney 	/*
1695098297b2SJeff Mahoney 	 * new format is limited by the 32 bit wide i_blocks field, want to
1696098297b2SJeff Mahoney 	 * be one full block below that.
16971da177e4SLinus Torvalds 	 */
16981da177e4SLinus Torvalds 	s->s_maxbytes = (512LL << 32) - s->s_blocksize;
16991da177e4SLinus Torvalds 	return 0;
17001da177e4SLinus Torvalds }
17011da177e4SLinus Torvalds 
17021da177e4SLinus Torvalds /* after journal replay, reread all bitmap and super blocks */
reread_meta_blocks(struct super_block * s)1703bd4c625cSLinus Torvalds static int reread_meta_blocks(struct super_block *s)
1704bd4c625cSLinus Torvalds {
1705d554822eSZhang Yi 	if (bh_read(SB_BUFFER_WITH_SB(s), 0) < 0) {
170645b03d5eSJeff Mahoney 		reiserfs_warning(s, "reiserfs-2504", "error reading the super");
17071da177e4SLinus Torvalds 		return 1;
17081da177e4SLinus Torvalds 	}
17091da177e4SLinus Torvalds 
17101da177e4SLinus Torvalds 	return 0;
17111da177e4SLinus Torvalds }
17121da177e4SLinus Torvalds 
1713098297b2SJeff Mahoney /* hash detection stuff */
17141da177e4SLinus Torvalds 
1715098297b2SJeff Mahoney /*
1716098297b2SJeff Mahoney  * if root directory is empty - we set default - Yura's - hash and
1717098297b2SJeff Mahoney  * warn about it
1718098297b2SJeff Mahoney  * FIXME: we look for only one name in a directory. If tea and yura
1719098297b2SJeff Mahoney  * both have the same value - we ask user to send report to the
1720098297b2SJeff Mahoney  * mailing list
1721098297b2SJeff Mahoney  */
find_hash_out(struct super_block * s)17221da177e4SLinus Torvalds static __u32 find_hash_out(struct super_block *s)
17231da177e4SLinus Torvalds {
17241da177e4SLinus Torvalds 	int retval;
17251da177e4SLinus Torvalds 	struct inode *inode;
17261da177e4SLinus Torvalds 	struct cpu_key key;
17271da177e4SLinus Torvalds 	INITIALIZE_PATH(path);
17281da177e4SLinus Torvalds 	struct reiserfs_dir_entry de;
1729c48138c2SJeff Mahoney 	struct reiserfs_de_head *deh;
17301da177e4SLinus Torvalds 	__u32 hash = DEFAULT_HASH;
1731c48138c2SJeff Mahoney 	__u32 deh_hashval, teahash, r5hash, yurahash;
17321da177e4SLinus Torvalds 
17332b0143b5SDavid Howells 	inode = d_inode(s->s_root);
17341da177e4SLinus Torvalds 
17351da177e4SLinus Torvalds 	make_cpu_key(&key, inode, ~0, TYPE_DIRENTRY, 3);
17361da177e4SLinus Torvalds 	retval = search_by_entry_key(s, &key, &path, &de);
17371da177e4SLinus Torvalds 	if (retval == IO_ERROR) {
17381da177e4SLinus Torvalds 		pathrelse(&path);
17391da177e4SLinus Torvalds 		return UNSET_HASH;
17401da177e4SLinus Torvalds 	}
17411da177e4SLinus Torvalds 	if (retval == NAME_NOT_FOUND)
17421da177e4SLinus Torvalds 		de.de_entry_num--;
1743c48138c2SJeff Mahoney 
17441da177e4SLinus Torvalds 	set_de_name_and_namelen(&de);
1745c48138c2SJeff Mahoney 	deh = de.de_deh + de.de_entry_num;
1746c48138c2SJeff Mahoney 
1747c48138c2SJeff Mahoney 	if (deh_offset(deh) == DOT_DOT_OFFSET) {
17481da177e4SLinus Torvalds 		/* allow override in this case */
1749c48138c2SJeff Mahoney 		if (reiserfs_rupasov_hash(s))
17501da177e4SLinus Torvalds 			hash = YURA_HASH;
1751c48138c2SJeff Mahoney 		reiserfs_info(s, "FS seems to be empty, autodetect is using the default hash\n");
1752c48138c2SJeff Mahoney 		goto out;
17531da177e4SLinus Torvalds 	}
1754c48138c2SJeff Mahoney 
1755c48138c2SJeff Mahoney 	deh_hashval = GET_HASH_VALUE(deh_offset(deh));
17561da177e4SLinus Torvalds 	r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen));
17571da177e4SLinus Torvalds 	teahash = GET_HASH_VALUE(keyed_hash(de.de_name, de.de_namelen));
17581da177e4SLinus Torvalds 	yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen));
1759c48138c2SJeff Mahoney 
1760c48138c2SJeff Mahoney 	if ((teahash == r5hash && deh_hashval == r5hash) ||
1761c48138c2SJeff Mahoney 	    (teahash == yurahash && deh_hashval == yurahash) ||
1762c48138c2SJeff Mahoney 	    (r5hash == yurahash && deh_hashval == yurahash)) {
1763c48138c2SJeff Mahoney 		reiserfs_warning(s, "reiserfs-2506",
1764c48138c2SJeff Mahoney 				 "Unable to automatically detect hash "
1765c48138c2SJeff Mahoney 				 "function. Please mount with -o "
176645b03d5eSJeff Mahoney 				 "hash={tea,rupasov,r5}");
17671da177e4SLinus Torvalds 		hash = UNSET_HASH;
1768c48138c2SJeff Mahoney 		goto out;
17691da177e4SLinus Torvalds 	}
1770c48138c2SJeff Mahoney 
1771c48138c2SJeff Mahoney 	if (deh_hashval == yurahash)
17721da177e4SLinus Torvalds 		hash = YURA_HASH;
1773c48138c2SJeff Mahoney 	else if (deh_hashval == teahash)
17741da177e4SLinus Torvalds 		hash = TEA_HASH;
1775c48138c2SJeff Mahoney 	else if (deh_hashval == r5hash)
17761da177e4SLinus Torvalds 		hash = R5_HASH;
17771da177e4SLinus Torvalds 	else {
177845b03d5eSJeff Mahoney 		reiserfs_warning(s, "reiserfs-2506",
177945b03d5eSJeff Mahoney 				 "Unrecognised hash function");
17801da177e4SLinus Torvalds 		hash = UNSET_HASH;
17811da177e4SLinus Torvalds 	}
1782c48138c2SJeff Mahoney out:
17831da177e4SLinus Torvalds 	pathrelse(&path);
17841da177e4SLinus Torvalds 	return hash;
17851da177e4SLinus Torvalds }
17861da177e4SLinus Torvalds 
1787098297b2SJeff Mahoney /* finds out which hash names are sorted with */
what_hash(struct super_block * s)17881da177e4SLinus Torvalds static int what_hash(struct super_block *s)
17891da177e4SLinus Torvalds {
17901da177e4SLinus Torvalds 	__u32 code;
17911da177e4SLinus Torvalds 
17921da177e4SLinus Torvalds 	code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(s));
17931da177e4SLinus Torvalds 
1794098297b2SJeff Mahoney 	/*
1795098297b2SJeff Mahoney 	 * reiserfs_hash_detect() == true if any of the hash mount options
1796098297b2SJeff Mahoney 	 * were used.  We must check them to make sure the user isn't
1797098297b2SJeff Mahoney 	 * using a bad hash value
17981da177e4SLinus Torvalds 	 */
17991da177e4SLinus Torvalds 	if (code == UNSET_HASH || reiserfs_hash_detect(s))
18001da177e4SLinus Torvalds 		code = find_hash_out(s);
18011da177e4SLinus Torvalds 
18021da177e4SLinus Torvalds 	if (code != UNSET_HASH && reiserfs_hash_detect(s)) {
1803098297b2SJeff Mahoney 		/*
1804098297b2SJeff Mahoney 		 * detection has found the hash, and we must check against the
1805098297b2SJeff Mahoney 		 * mount options
18061da177e4SLinus Torvalds 		 */
18071da177e4SLinus Torvalds 		if (reiserfs_rupasov_hash(s) && code != YURA_HASH) {
180845b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2507",
180945b03d5eSJeff Mahoney 					 "Error, %s hash detected, "
1810bd4c625cSLinus Torvalds 					 "unable to force rupasov hash",
1811bd4c625cSLinus Torvalds 					 reiserfs_hashname(code));
18121da177e4SLinus Torvalds 			code = UNSET_HASH;
18131da177e4SLinus Torvalds 		} else if (reiserfs_tea_hash(s) && code != TEA_HASH) {
181445b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2508",
181545b03d5eSJeff Mahoney 					 "Error, %s hash detected, "
1816bd4c625cSLinus Torvalds 					 "unable to force tea hash",
1817bd4c625cSLinus Torvalds 					 reiserfs_hashname(code));
18181da177e4SLinus Torvalds 			code = UNSET_HASH;
18191da177e4SLinus Torvalds 		} else if (reiserfs_r5_hash(s) && code != R5_HASH) {
182045b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2509",
182145b03d5eSJeff Mahoney 					 "Error, %s hash detected, "
1822bd4c625cSLinus Torvalds 					 "unable to force r5 hash",
1823bd4c625cSLinus Torvalds 					 reiserfs_hashname(code));
18241da177e4SLinus Torvalds 			code = UNSET_HASH;
18251da177e4SLinus Torvalds 		}
18261da177e4SLinus Torvalds 	} else {
1827098297b2SJeff Mahoney 		/*
1828098297b2SJeff Mahoney 		 * find_hash_out was not called or
1829098297b2SJeff Mahoney 		 * could not determine the hash
1830098297b2SJeff Mahoney 		 */
18311da177e4SLinus Torvalds 		if (reiserfs_rupasov_hash(s)) {
18321da177e4SLinus Torvalds 			code = YURA_HASH;
18331da177e4SLinus Torvalds 		} else if (reiserfs_tea_hash(s)) {
18341da177e4SLinus Torvalds 			code = TEA_HASH;
18351da177e4SLinus Torvalds 		} else if (reiserfs_r5_hash(s)) {
18361da177e4SLinus Torvalds 			code = R5_HASH;
18371da177e4SLinus Torvalds 		}
18381da177e4SLinus Torvalds 	}
18391da177e4SLinus Torvalds 
1840098297b2SJeff Mahoney 	/*
1841098297b2SJeff Mahoney 	 * if we are mounted RW, and we have a new valid hash code, update
1842098297b2SJeff Mahoney 	 * the super
18431da177e4SLinus Torvalds 	 */
18441da177e4SLinus Torvalds 	if (code != UNSET_HASH &&
1845bc98a42cSDavid Howells 	    !sb_rdonly(s) &&
18461da177e4SLinus Torvalds 	    code != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) {
18471da177e4SLinus Torvalds 		set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code);
18481da177e4SLinus Torvalds 	}
18491da177e4SLinus Torvalds 	return code;
18501da177e4SLinus Torvalds }
18511da177e4SLinus Torvalds 
1852098297b2SJeff Mahoney /* return pointer to appropriate function */
hash_function(struct super_block * s)18531da177e4SLinus Torvalds static hashf_t hash_function(struct super_block *s)
18541da177e4SLinus Torvalds {
18551da177e4SLinus Torvalds 	switch (what_hash(s)) {
18561da177e4SLinus Torvalds 	case TEA_HASH:
18571da177e4SLinus Torvalds 		reiserfs_info(s, "Using tea hash to sort names\n");
18581da177e4SLinus Torvalds 		return keyed_hash;
18591da177e4SLinus Torvalds 	case YURA_HASH:
18601da177e4SLinus Torvalds 		reiserfs_info(s, "Using rupasov hash to sort names\n");
18611da177e4SLinus Torvalds 		return yura_hash;
18621da177e4SLinus Torvalds 	case R5_HASH:
18631da177e4SLinus Torvalds 		reiserfs_info(s, "Using r5 hash to sort names\n");
18641da177e4SLinus Torvalds 		return r5_hash;
18651da177e4SLinus Torvalds 	}
18661da177e4SLinus Torvalds 	return NULL;
18671da177e4SLinus Torvalds }
18681da177e4SLinus Torvalds 
1869098297b2SJeff Mahoney /* this is used to set up correct value for old partitions */
function2code(hashf_t func)18701da177e4SLinus Torvalds static int function2code(hashf_t func)
18711da177e4SLinus Torvalds {
18721da177e4SLinus Torvalds 	if (func == keyed_hash)
18731da177e4SLinus Torvalds 		return TEA_HASH;
18741da177e4SLinus Torvalds 	if (func == yura_hash)
18751da177e4SLinus Torvalds 		return YURA_HASH;
18761da177e4SLinus Torvalds 	if (func == r5_hash)
18771da177e4SLinus Torvalds 		return R5_HASH;
18781da177e4SLinus Torvalds 
1879098297b2SJeff Mahoney 	BUG();			/* should never happen */
18801da177e4SLinus Torvalds 
18811da177e4SLinus Torvalds 	return 0;
18821da177e4SLinus Torvalds }
18831da177e4SLinus Torvalds 
188445b03d5eSJeff Mahoney #define SWARN(silent, s, id, ...)			\
18851da177e4SLinus Torvalds 	if (!(silent))				\
188645b03d5eSJeff Mahoney 		reiserfs_warning(s, id, __VA_ARGS__)
18871da177e4SLinus Torvalds 
reiserfs_fill_super(struct super_block * s,void * data,int silent)18881da177e4SLinus Torvalds static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
18891da177e4SLinus Torvalds {
18901da177e4SLinus Torvalds 	struct inode *root_inode;
18911da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
18921da177e4SLinus Torvalds 	int old_format = 0;
18931da177e4SLinus Torvalds 	unsigned long blocks;
18941da177e4SLinus Torvalds 	unsigned int commit_max_age = 0;
18951da177e4SLinus Torvalds 	int jinit_done = 0;
18961da177e4SLinus Torvalds 	struct reiserfs_iget_args args;
18971da177e4SLinus Torvalds 	struct reiserfs_super_block *rs;
18981da177e4SLinus Torvalds 	char *jdev_name;
18991da177e4SLinus Torvalds 	struct reiserfs_sb_info *sbi;
19001da177e4SLinus Torvalds 	int errval = -EINVAL;
1901aca60617SJan Kara 	char *qf_names[REISERFS_MAXQUOTAS] = {};
190200b44197SJan Kara 	unsigned int qfmt = 0;
19031da177e4SLinus Torvalds 
190401afb213SYan Burman 	sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL);
1905b7b7fa43SJeff Mahoney 	if (!sbi)
1906b7b7fa43SJeff Mahoney 		return -ENOMEM;
19071da177e4SLinus Torvalds 	s->s_fs_info = sbi;
19081da177e4SLinus Torvalds 	/* Set default values for options: non-aggressive tails, RO on errors */
1909efaa33ebSArtem Bityutskiy 	sbi->s_mount_opt |= (1 << REISERFS_SMALLTAIL);
1910efaa33ebSArtem Bityutskiy 	sbi->s_mount_opt |= (1 << REISERFS_ERROR_RO);
1911efaa33ebSArtem Bityutskiy 	sbi->s_mount_opt |= (1 << REISERFS_BARRIER_FLUSH);
1912098297b2SJeff Mahoney 	/* no preallocation minimum, be smart in reiserfs_file_write instead */
1913efaa33ebSArtem Bityutskiy 	sbi->s_alloc_options.preallocmin = 0;
19141da177e4SLinus Torvalds 	/* Preallocate by 16 blocks (17-1) at once */
1915efaa33ebSArtem Bityutskiy 	sbi->s_alloc_options.preallocsize = 17;
19161da177e4SLinus Torvalds 	/* setup default block allocator options */
19171da177e4SLinus Torvalds 	reiserfs_init_alloc_options(s);
19181da177e4SLinus Torvalds 
1919033369d1SArtem Bityutskiy 	spin_lock_init(&sbi->old_work_lock);
1920033369d1SArtem Bityutskiy 	INIT_DELAYED_WORK(&sbi->old_work, flush_old_commits);
1921efaa33ebSArtem Bityutskiy 	mutex_init(&sbi->lock);
1922efaa33ebSArtem Bityutskiy 	sbi->lock_depth = -1;
19238ebc4232SFrederic Weisbecker 
1924797d9016SJeff Mahoney 	sbi->commit_wq = alloc_workqueue("reiserfs/%s", WQ_MEM_RECLAIM, 0,
1925797d9016SJeff Mahoney 					 s->s_id);
1926797d9016SJeff Mahoney 	if (!sbi->commit_wq) {
1927797d9016SJeff Mahoney 		SWARN(silent, s, "", "Cannot allocate commit workqueue");
1928797d9016SJeff Mahoney 		errval = -ENOMEM;
1929797d9016SJeff Mahoney 		goto error_unlocked;
1930797d9016SJeff Mahoney 	}
1931797d9016SJeff Mahoney 
19321da177e4SLinus Torvalds 	jdev_name = NULL;
1933bd4c625cSLinus Torvalds 	if (reiserfs_parse_options
1934a228bf8fSJeff Mahoney 	    (s, (char *)data, &sbi->s_mount_opt, &blocks, &jdev_name,
193500b44197SJan Kara 	     &commit_max_age, qf_names, &qfmt) == 0) {
1936f32485beSFrederic Weisbecker 		goto error_unlocked;
19371da177e4SLinus Torvalds 	}
1938c3aa0776SJan Kara 	if (jdev_name && jdev_name[0]) {
1939efaa33ebSArtem Bityutskiy 		sbi->s_jdev = kstrdup(jdev_name, GFP_KERNEL);
1940efaa33ebSArtem Bityutskiy 		if (!sbi->s_jdev) {
1941c3aa0776SJan Kara 			SWARN(silent, s, "", "Cannot allocate memory for "
1942c3aa0776SJan Kara 				"journal device name");
19434d5c1adaSJan Kara 			goto error_unlocked;
1944c3aa0776SJan Kara 		}
1945c3aa0776SJan Kara 	}
194600b44197SJan Kara #ifdef CONFIG_QUOTA
194700b44197SJan Kara 	handle_quota_files(s, qf_names, &qfmt);
194800b44197SJan Kara #endif
19491da177e4SLinus Torvalds 
19501da177e4SLinus Torvalds 	if (blocks) {
195145b03d5eSJeff Mahoney 		SWARN(silent, s, "jmacd-7", "resize option for remount only");
1952f32485beSFrederic Weisbecker 		goto error_unlocked;
19531da177e4SLinus Torvalds 	}
19541da177e4SLinus Torvalds 
1955098297b2SJeff Mahoney 	/*
1956098297b2SJeff Mahoney 	 * try old format (undistributed bitmap, super block in 8-th 1k
1957098297b2SJeff Mahoney 	 * block of a device)
1958098297b2SJeff Mahoney 	 */
19591da177e4SLinus Torvalds 	if (!read_super_block(s, REISERFS_OLD_DISK_OFFSET_IN_BYTES))
19601da177e4SLinus Torvalds 		old_format = 1;
1961098297b2SJeff Mahoney 
1962098297b2SJeff Mahoney 	/*
1963098297b2SJeff Mahoney 	 * try new format (64-th 1k block), which can contain reiserfs
1964098297b2SJeff Mahoney 	 * super block
1965098297b2SJeff Mahoney 	 */
19661da177e4SLinus Torvalds 	else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) {
196745b03d5eSJeff Mahoney 		SWARN(silent, s, "sh-2021", "can not find reiserfs on %s",
19682ccdc413SAl Viro 		      s->s_id);
1969f32485beSFrederic Weisbecker 		goto error_unlocked;
19701da177e4SLinus Torvalds 	}
19711da177e4SLinus Torvalds 
197222b13969SDeepa Dinamani 	s->s_time_min = 0;
197322b13969SDeepa Dinamani 	s->s_time_max = U32_MAX;
197422b13969SDeepa Dinamani 
19751da177e4SLinus Torvalds 	rs = SB_DISK_SUPER_BLOCK(s);
1976098297b2SJeff Mahoney 	/*
1977098297b2SJeff Mahoney 	 * Let's do basic sanity check to verify that underlying device is not
1978098297b2SJeff Mahoney 	 * smaller than the filesystem. If the check fails then abort and
1979098297b2SJeff Mahoney 	 * scream, because bad stuff will happen otherwise.
1980098297b2SJeff Mahoney 	 */
19811d5dd3b9SChristoph Hellwig 	if (bdev_nr_bytes(s->s_bdev) < sb_block_count(rs) * sb_blocksize(rs)) {
198245b03d5eSJeff Mahoney 		SWARN(silent, s, "", "Filesystem cannot be "
198345b03d5eSJeff Mahoney 		      "mounted because it is bigger than the device");
198445b03d5eSJeff Mahoney 		SWARN(silent, s, "", "You may need to run fsck "
198545b03d5eSJeff Mahoney 		      "or increase size of your LVM partition");
198645b03d5eSJeff Mahoney 		SWARN(silent, s, "", "Or may be you forgot to "
198745b03d5eSJeff Mahoney 		      "reboot after fdisk when it told you to");
1988f32485beSFrederic Weisbecker 		goto error_unlocked;
19891da177e4SLinus Torvalds 	}
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 	sbi->s_mount_state = SB_REISERFS_STATE(s);
19921da177e4SLinus Torvalds 	sbi->s_mount_state = REISERFS_VALID_FS;
19931da177e4SLinus Torvalds 
19946f01046bSJeff Mahoney 	if ((errval = reiserfs_init_bitmap_cache(s))) {
199545b03d5eSJeff Mahoney 		SWARN(silent, s, "jmacd-8", "unable to read bitmap");
1996f32485beSFrederic Weisbecker 		goto error_unlocked;
19971da177e4SLinus Torvalds 	}
1998f32485beSFrederic Weisbecker 
1999d2c89a42SJeff Mahoney 	errval = -EINVAL;
20001da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
200145b03d5eSJeff Mahoney 	SWARN(silent, s, "", "CONFIG_REISERFS_CHECK is set ON");
200245b03d5eSJeff Mahoney 	SWARN(silent, s, "", "- it is slow mode for debugging.");
20031da177e4SLinus Torvalds #endif
20041da177e4SLinus Torvalds 
20051da177e4SLinus Torvalds 	/* make data=ordered the default */
20061da177e4SLinus Torvalds 	if (!reiserfs_data_log(s) && !reiserfs_data_ordered(s) &&
2007bd4c625cSLinus Torvalds 	    !reiserfs_data_writeback(s)) {
2008efaa33ebSArtem Bityutskiy 		sbi->s_mount_opt |= (1 << REISERFS_DATA_ORDERED);
20091da177e4SLinus Torvalds 	}
20101da177e4SLinus Torvalds 
20111da177e4SLinus Torvalds 	if (reiserfs_data_log(s)) {
20121da177e4SLinus Torvalds 		reiserfs_info(s, "using journaled data mode\n");
20131da177e4SLinus Torvalds 	} else if (reiserfs_data_ordered(s)) {
20141da177e4SLinus Torvalds 		reiserfs_info(s, "using ordered data mode\n");
20151da177e4SLinus Torvalds 	} else {
20161da177e4SLinus Torvalds 		reiserfs_info(s, "using writeback data mode\n");
20171da177e4SLinus Torvalds 	}
20181da177e4SLinus Torvalds 	if (reiserfs_barrier_flush(s)) {
20191da177e4SLinus Torvalds 		printk("reiserfs: using flush barriers\n");
20201da177e4SLinus Torvalds 	}
2021f32485beSFrederic Weisbecker 
202237c69b98SFrederic Weisbecker 	if (journal_init(s, jdev_name, old_format, commit_max_age)) {
202337c69b98SFrederic Weisbecker 		SWARN(silent, s, "sh-2022",
202437c69b98SFrederic Weisbecker 		      "unable to initialize journal space");
202537c69b98SFrederic Weisbecker 		goto error_unlocked;
202637c69b98SFrederic Weisbecker 	} else {
2027098297b2SJeff Mahoney 		/*
2028098297b2SJeff Mahoney 		 * once this is set, journal_release must be called
2029098297b2SJeff Mahoney 		 * if we error out of the mount
203037c69b98SFrederic Weisbecker 		 */
2031098297b2SJeff Mahoney 		jinit_done = 1;
203237c69b98SFrederic Weisbecker 	}
203337c69b98SFrederic Weisbecker 
20341da177e4SLinus Torvalds 	if (reread_meta_blocks(s)) {
203545b03d5eSJeff Mahoney 		SWARN(silent, s, "jmacd-9",
203645b03d5eSJeff Mahoney 		      "unable to reread meta blocks after journal init");
20379b467e6eSFrederic Weisbecker 		goto error_unlocked;
20381da177e4SLinus Torvalds 	}
20391da177e4SLinus Torvalds 
20401da177e4SLinus Torvalds 	if (replay_only(s))
20419b467e6eSFrederic Weisbecker 		goto error_unlocked;
20421da177e4SLinus Torvalds 
204360e4cf67SJeff Mahoney 	s->s_xattr = reiserfs_xattr_handlers;
204460e4cf67SJeff Mahoney 
2045bc98a42cSDavid Howells 	if (bdev_read_only(s->s_bdev) && !sb_rdonly(s)) {
204645b03d5eSJeff Mahoney 		SWARN(silent, s, "clm-7000",
204745b03d5eSJeff Mahoney 		      "Detected readonly device, marking FS readonly");
20481751e8a6SLinus Torvalds 		s->s_flags |= SB_RDONLY;
20491da177e4SLinus Torvalds 	}
20501da177e4SLinus Torvalds 	args.objectid = REISERFS_ROOT_OBJECTID;
20511da177e4SLinus Torvalds 	args.dirid = REISERFS_ROOT_PARENT_OBJECTID;
2052bd4c625cSLinus Torvalds 	root_inode =
2053bd4c625cSLinus Torvalds 	    iget5_locked(s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor,
2054a228bf8fSJeff Mahoney 			 reiserfs_init_locked_inode, (void *)&args);
20551da177e4SLinus Torvalds 	if (!root_inode) {
205645b03d5eSJeff Mahoney 		SWARN(silent, s, "jmacd-10", "get root inode failed");
20579b467e6eSFrederic Weisbecker 		goto error_unlocked;
20581da177e4SLinus Torvalds 	}
20591da177e4SLinus Torvalds 
20609b467e6eSFrederic Weisbecker 	/*
20619b467e6eSFrederic Weisbecker 	 * This path assumed to be called with the BKL in the old times.
20629b467e6eSFrederic Weisbecker 	 * Now we have inherited the big reiserfs lock from it and many
20639b467e6eSFrederic Weisbecker 	 * reiserfs helpers called in the mount path and elsewhere require
20649b467e6eSFrederic Weisbecker 	 * this lock to be held even if it's not always necessary. Let's be
20659b467e6eSFrederic Weisbecker 	 * conservative and hold it early. The window can be reduced after
20669b467e6eSFrederic Weisbecker 	 * careful review of the code.
20679b467e6eSFrederic Weisbecker 	 */
20689b467e6eSFrederic Weisbecker 	reiserfs_write_lock(s);
20699b467e6eSFrederic Weisbecker 
20701da177e4SLinus Torvalds 	if (root_inode->i_state & I_NEW) {
20711da177e4SLinus Torvalds 		reiserfs_read_locked_inode(root_inode, &args);
20721da177e4SLinus Torvalds 		unlock_new_inode(root_inode);
20731da177e4SLinus Torvalds 	}
20741da177e4SLinus Torvalds 
20752acf15b9SYu Kuai 	if (!S_ISDIR(root_inode->i_mode) || !inode_get_bytes(root_inode) ||
20762acf15b9SYu Kuai 	    !root_inode->i_size) {
20772acf15b9SYu Kuai 		SWARN(silent, s, "", "corrupt root inode, run fsck");
20782acf15b9SYu Kuai 		iput(root_inode);
20792acf15b9SYu Kuai 		errval = -EUCLEAN;
20802acf15b9SYu Kuai 		goto error;
20812acf15b9SYu Kuai 	}
20822acf15b9SYu Kuai 
208348fde701SAl Viro 	s->s_root = d_make_root(root_inode);
208448fde701SAl Viro 	if (!s->s_root)
20851da177e4SLinus Torvalds 		goto error;
2086098297b2SJeff Mahoney 	/* define and initialize hash function */
20871da177e4SLinus Torvalds 	sbi->s_hash_function = hash_function(s);
20881da177e4SLinus Torvalds 	if (sbi->s_hash_function == NULL) {
20891da177e4SLinus Torvalds 		dput(s->s_root);
20901da177e4SLinus Torvalds 		s->s_root = NULL;
20911da177e4SLinus Torvalds 		goto error;
20921da177e4SLinus Torvalds 	}
20931da177e4SLinus Torvalds 
2094bd4c625cSLinus Torvalds 	if (is_reiserfs_3_5(rs)
2095bd4c625cSLinus Torvalds 	    || (is_reiserfs_jr(rs) && SB_VERSION(s) == REISERFS_VERSION_1))
2096a228bf8fSJeff Mahoney 		set_bit(REISERFS_3_5, &sbi->s_properties);
2097e1fabd3cSJeff Mahoney 	else if (old_format)
2098a228bf8fSJeff Mahoney 		set_bit(REISERFS_OLD_FORMAT, &sbi->s_properties);
20991da177e4SLinus Torvalds 	else
2100a228bf8fSJeff Mahoney 		set_bit(REISERFS_3_6, &sbi->s_properties);
21011da177e4SLinus Torvalds 
2102bc98a42cSDavid Howells 	if (!sb_rdonly(s)) {
21031da177e4SLinus Torvalds 
21041da177e4SLinus Torvalds 		errval = journal_begin(&th, s, 1);
21051da177e4SLinus Torvalds 		if (errval) {
21061da177e4SLinus Torvalds 			dput(s->s_root);
21071da177e4SLinus Torvalds 			s->s_root = NULL;
21081da177e4SLinus Torvalds 			goto error;
21091da177e4SLinus Torvalds 		}
21101da177e4SLinus Torvalds 		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
21111da177e4SLinus Torvalds 
21121da177e4SLinus Torvalds 		set_sb_umount_state(rs, REISERFS_ERROR_FS);
21131da177e4SLinus Torvalds 		set_sb_fs_state(rs, 0);
21141da177e4SLinus Torvalds 
2115098297b2SJeff Mahoney 		/*
2116098297b2SJeff Mahoney 		 * Clear out s_bmap_nr if it would wrap. We can handle this
2117cb680c1bSJeff Mahoney 		 * case, but older revisions can't. This will cause the
2118cb680c1bSJeff Mahoney 		 * file system to fail mount on those older implementations,
2119098297b2SJeff Mahoney 		 * avoiding corruption. -jeffm
2120098297b2SJeff Mahoney 		 */
2121cb680c1bSJeff Mahoney 		if (bmap_would_wrap(reiserfs_bmap_count(s)) &&
2122cb680c1bSJeff Mahoney 		    sb_bmap_nr(rs) != 0) {
212345b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-2030", "This file system "
2124cb680c1bSJeff Mahoney 					"claims to use %u bitmap blocks in "
2125cb680c1bSJeff Mahoney 					"its super block, but requires %u. "
2126cb680c1bSJeff Mahoney 					"Clearing to zero.", sb_bmap_nr(rs),
2127cb680c1bSJeff Mahoney 					reiserfs_bmap_count(s));
2128cb680c1bSJeff Mahoney 
2129cb680c1bSJeff Mahoney 			set_sb_bmap_nr(rs, 0);
2130cb680c1bSJeff Mahoney 		}
2131cb680c1bSJeff Mahoney 
21321da177e4SLinus Torvalds 		if (old_format_only(s)) {
2133098297b2SJeff Mahoney 			/*
2134098297b2SJeff Mahoney 			 * filesystem of format 3.5 either with standard
2135098297b2SJeff Mahoney 			 * or non-standard journal
2136098297b2SJeff Mahoney 			 */
21371da177e4SLinus Torvalds 			if (convert_reiserfs(s)) {
21381da177e4SLinus Torvalds 				/* and -o conv is given */
21391da177e4SLinus Torvalds 				if (!silent)
2140bd4c625cSLinus Torvalds 					reiserfs_info(s,
2141bd4c625cSLinus Torvalds 						      "converting 3.5 filesystem to the 3.6 format");
21421da177e4SLinus Torvalds 
21431da177e4SLinus Torvalds 				if (is_reiserfs_3_5(rs))
2144098297b2SJeff Mahoney 					/*
2145098297b2SJeff Mahoney 					 * put magic string of 3.6 format.
2146098297b2SJeff Mahoney 					 * 2.2 will not be able to
2147098297b2SJeff Mahoney 					 * mount this filesystem anymore
2148098297b2SJeff Mahoney 					 */
2149bd4c625cSLinus Torvalds 					memcpy(rs->s_v1.s_magic,
2150bd4c625cSLinus Torvalds 					       reiserfs_3_6_magic_string,
2151bd4c625cSLinus Torvalds 					       sizeof
2152bd4c625cSLinus Torvalds 					       (reiserfs_3_6_magic_string));
21531da177e4SLinus Torvalds 
21541da177e4SLinus Torvalds 				set_sb_version(rs, REISERFS_VERSION_2);
21551da177e4SLinus Torvalds 				reiserfs_convert_objectid_map_v1(s);
2156a228bf8fSJeff Mahoney 				set_bit(REISERFS_3_6, &sbi->s_properties);
2157a228bf8fSJeff Mahoney 				clear_bit(REISERFS_3_5, &sbi->s_properties);
21581da177e4SLinus Torvalds 			} else if (!silent) {
21591da177e4SLinus Torvalds 				reiserfs_info(s, "using 3.5.x disk format\n");
21601da177e4SLinus Torvalds 			}
2161702d21c6SJeff Mahoney 		} else
2162702d21c6SJeff Mahoney 			set_sb_mnt_count(rs, sb_mnt_count(rs) + 1);
2163702d21c6SJeff Mahoney 
21641da177e4SLinus Torvalds 
216509f1b80bSJeff Mahoney 		journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));
216658d85426SJeff Mahoney 		errval = journal_end(&th);
21671da177e4SLinus Torvalds 		if (errval) {
21681da177e4SLinus Torvalds 			dput(s->s_root);
21691da177e4SLinus Torvalds 			s->s_root = NULL;
21701da177e4SLinus Torvalds 			goto error;
21711da177e4SLinus Torvalds 		}
21721da177e4SLinus Torvalds 
21734c05141dSJeff Mahoney 		reiserfs_write_unlock(s);
2174edcc37a0SAl Viro 		if ((errval = reiserfs_lookup_privroot(s)) ||
2175edcc37a0SAl Viro 		    (errval = reiserfs_xattr_init(s, s->s_flags))) {
21761da177e4SLinus Torvalds 			dput(s->s_root);
21771da177e4SLinus Torvalds 			s->s_root = NULL;
21784c05141dSJeff Mahoney 			goto error_unlocked;
21791da177e4SLinus Torvalds 		}
21804c05141dSJeff Mahoney 		reiserfs_write_lock(s);
21811da177e4SLinus Torvalds 
2182098297b2SJeff Mahoney 		/*
2183098297b2SJeff Mahoney 		 * look for files which were to be removed in previous session
2184098297b2SJeff Mahoney 		 */
21851da177e4SLinus Torvalds 		finish_unfinished(s);
21861da177e4SLinus Torvalds 	} else {
21871da177e4SLinus Torvalds 		if (old_format_only(s) && !silent) {
21881da177e4SLinus Torvalds 			reiserfs_info(s, "using 3.5.x disk format\n");
21891da177e4SLinus Torvalds 		}
21901da177e4SLinus Torvalds 
21914c05141dSJeff Mahoney 		reiserfs_write_unlock(s);
2192edcc37a0SAl Viro 		if ((errval = reiserfs_lookup_privroot(s)) ||
2193edcc37a0SAl Viro 		    (errval = reiserfs_xattr_init(s, s->s_flags))) {
21941da177e4SLinus Torvalds 			dput(s->s_root);
21951da177e4SLinus Torvalds 			s->s_root = NULL;
21964c05141dSJeff Mahoney 			goto error_unlocked;
21971da177e4SLinus Torvalds 		}
21984c05141dSJeff Mahoney 		reiserfs_write_lock(s);
21991da177e4SLinus Torvalds 	}
2200098297b2SJeff Mahoney 	/*
2201098297b2SJeff Mahoney 	 * mark hash in super block: it could be unset. overwrite should be ok
2202098297b2SJeff Mahoney 	 */
22031da177e4SLinus Torvalds 	set_sb_hash_function_code(rs, function2code(sbi->s_hash_function));
22041da177e4SLinus Torvalds 
22051da177e4SLinus Torvalds 	handle_attrs(s);
22061da177e4SLinus Torvalds 
22071da177e4SLinus Torvalds 	reiserfs_proc_info_init(s);
22081da177e4SLinus Torvalds 
22091da177e4SLinus Torvalds 	init_waitqueue_head(&(sbi->s_wait));
22101da177e4SLinus Torvalds 	spin_lock_init(&sbi->bitmap_lock);
22111da177e4SLinus Torvalds 
22128ebc4232SFrederic Weisbecker 	reiserfs_write_unlock(s);
22138ebc4232SFrederic Weisbecker 
22141da177e4SLinus Torvalds 	return (0);
22151da177e4SLinus Torvalds 
22161da177e4SLinus Torvalds error:
2217b7b7fa43SJeff Mahoney 	reiserfs_write_unlock(s);
2218b7b7fa43SJeff Mahoney 
2219f32485beSFrederic Weisbecker error_unlocked:
2220f32485beSFrederic Weisbecker 	/* kill the commit thread, free journal ram */
2221f32485beSFrederic Weisbecker 	if (jinit_done) {
2222f32485beSFrederic Weisbecker 		reiserfs_write_lock(s);
2223f32485beSFrederic Weisbecker 		journal_release_error(NULL, s);
2224f32485beSFrederic Weisbecker 		reiserfs_write_unlock(s);
2225f32485beSFrederic Weisbecker 	}
2226f32485beSFrederic Weisbecker 
2227fa0c5540SJiri Slaby 	if (sbi->commit_wq)
2228fa0c5540SJiri Slaby 		destroy_workqueue(sbi->commit_wq);
2229fa0c5540SJiri Slaby 
223071b0576bSJan Kara 	reiserfs_cancel_old_flush(s);
2231033369d1SArtem Bityutskiy 
22325065227bSJeff Mahoney 	reiserfs_free_bitmap_cache(s);
22331da177e4SLinus Torvalds 	if (SB_BUFFER_WITH_SB(s))
22341da177e4SLinus Torvalds 		brelse(SB_BUFFER_WITH_SB(s));
22351da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
22365065227bSJeff Mahoney 	{
22375065227bSJeff Mahoney 		int j;
2238aca60617SJan Kara 		for (j = 0; j < REISERFS_MAXQUOTAS; j++)
223900b44197SJan Kara 			kfree(qf_names[j]);
22405065227bSJeff Mahoney 	}
22411da177e4SLinus Torvalds #endif
22425474ca7dSJan Kara 	kfree(sbi->s_jdev);
22431da177e4SLinus Torvalds 	kfree(sbi);
22441da177e4SLinus Torvalds 
22451da177e4SLinus Torvalds 	s->s_fs_info = NULL;
22461da177e4SLinus Torvalds 	return errval;
22471da177e4SLinus Torvalds }
22481da177e4SLinus Torvalds 
reiserfs_statfs(struct dentry * dentry,struct kstatfs * buf)2249726c3342SDavid Howells static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf)
22501da177e4SLinus Torvalds {
2251726c3342SDavid Howells 	struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(dentry->d_sb);
22521da177e4SLinus Torvalds 
22531da177e4SLinus Torvalds 	buf->f_namelen = (REISERFS_MAX_NAME(s->s_blocksize));
22541da177e4SLinus Torvalds 	buf->f_bfree = sb_free_blocks(rs);
22551da177e4SLinus Torvalds 	buf->f_bavail = buf->f_bfree;
22561da177e4SLinus Torvalds 	buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
2257726c3342SDavid Howells 	buf->f_bsize = dentry->d_sb->s_blocksize;
22581da177e4SLinus Torvalds 	/* changed to accommodate gcc folks. */
22591da177e4SLinus Torvalds 	buf->f_type = REISERFS_SUPER_MAGIC;
2260651d0623SColy Li 	buf->f_fsid.val[0] = (u32)crc32_le(0, rs->s_uuid, sizeof(rs->s_uuid)/2);
2261651d0623SColy Li 	buf->f_fsid.val[1] = (u32)crc32_le(0, rs->s_uuid + sizeof(rs->s_uuid)/2,
2262651d0623SColy Li 				sizeof(rs->s_uuid)/2);
2263651d0623SColy Li 
22641da177e4SLinus Torvalds 	return 0;
22651da177e4SLinus Torvalds }
22661da177e4SLinus Torvalds 
22671da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
reiserfs_write_dquot(struct dquot * dquot)22681da177e4SLinus Torvalds static int reiserfs_write_dquot(struct dquot *dquot)
22691da177e4SLinus Torvalds {
22701da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
2271bd6a1f16SJan Kara 	int ret, err;
2272d2d0395fSJeff Mahoney 	int depth;
22731da177e4SLinus Torvalds 
22741da177e4SLinus Torvalds 	reiserfs_write_lock(dquot->dq_sb);
2275bd4c625cSLinus Torvalds 	ret =
2276bd4c625cSLinus Torvalds 	    journal_begin(&th, dquot->dq_sb,
2277bd4c625cSLinus Torvalds 			  REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
2278bd6a1f16SJan Kara 	if (ret)
2279bd6a1f16SJan Kara 		goto out;
2280d2d0395fSJeff Mahoney 	depth = reiserfs_write_unlock_nested(dquot->dq_sb);
22811da177e4SLinus Torvalds 	ret = dquot_commit(dquot);
2282d2d0395fSJeff Mahoney 	reiserfs_write_lock_nested(dquot->dq_sb, depth);
228358d85426SJeff Mahoney 	err = journal_end(&th);
2284bd6a1f16SJan Kara 	if (!ret && err)
2285bd6a1f16SJan Kara 		ret = err;
2286bd6a1f16SJan Kara out:
22871da177e4SLinus Torvalds 	reiserfs_write_unlock(dquot->dq_sb);
22881da177e4SLinus Torvalds 	return ret;
22891da177e4SLinus Torvalds }
22901da177e4SLinus Torvalds 
reiserfs_acquire_dquot(struct dquot * dquot)22911da177e4SLinus Torvalds static int reiserfs_acquire_dquot(struct dquot *dquot)
22921da177e4SLinus Torvalds {
22931da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
2294bd6a1f16SJan Kara 	int ret, err;
2295d2d0395fSJeff Mahoney 	int depth;
22961da177e4SLinus Torvalds 
22971da177e4SLinus Torvalds 	reiserfs_write_lock(dquot->dq_sb);
2298bd4c625cSLinus Torvalds 	ret =
2299bd4c625cSLinus Torvalds 	    journal_begin(&th, dquot->dq_sb,
2300bd4c625cSLinus Torvalds 			  REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
2301bd6a1f16SJan Kara 	if (ret)
2302bd6a1f16SJan Kara 		goto out;
2303d2d0395fSJeff Mahoney 	depth = reiserfs_write_unlock_nested(dquot->dq_sb);
23041da177e4SLinus Torvalds 	ret = dquot_acquire(dquot);
2305d2d0395fSJeff Mahoney 	reiserfs_write_lock_nested(dquot->dq_sb, depth);
230658d85426SJeff Mahoney 	err = journal_end(&th);
2307bd6a1f16SJan Kara 	if (!ret && err)
2308bd6a1f16SJan Kara 		ret = err;
2309bd6a1f16SJan Kara out:
23101da177e4SLinus Torvalds 	reiserfs_write_unlock(dquot->dq_sb);
23111da177e4SLinus Torvalds 	return ret;
23121da177e4SLinus Torvalds }
23131da177e4SLinus Torvalds 
reiserfs_release_dquot(struct dquot * dquot)23141da177e4SLinus Torvalds static int reiserfs_release_dquot(struct dquot *dquot)
23151da177e4SLinus Torvalds {
23161da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
2317bd6a1f16SJan Kara 	int ret, err;
23181da177e4SLinus Torvalds 
23191da177e4SLinus Torvalds 	reiserfs_write_lock(dquot->dq_sb);
2320bd4c625cSLinus Torvalds 	ret =
2321bd4c625cSLinus Torvalds 	    journal_begin(&th, dquot->dq_sb,
2322bd4c625cSLinus Torvalds 			  REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
23237af11686SJan Kara 	reiserfs_write_unlock(dquot->dq_sb);
23249c3013e9SJan Kara 	if (ret) {
23259c3013e9SJan Kara 		/* Release dquot anyway to avoid endless cycle in dqput() */
23269c3013e9SJan Kara 		dquot_release(dquot);
2327bd6a1f16SJan Kara 		goto out;
23289c3013e9SJan Kara 	}
23291da177e4SLinus Torvalds 	ret = dquot_release(dquot);
23307af11686SJan Kara 	reiserfs_write_lock(dquot->dq_sb);
233158d85426SJeff Mahoney 	err = journal_end(&th);
2332bd6a1f16SJan Kara 	if (!ret && err)
2333bd6a1f16SJan Kara 		ret = err;
23341da177e4SLinus Torvalds 	reiserfs_write_unlock(dquot->dq_sb);
23357af11686SJan Kara out:
23361da177e4SLinus Torvalds 	return ret;
23371da177e4SLinus Torvalds }
23381da177e4SLinus Torvalds 
reiserfs_mark_dquot_dirty(struct dquot * dquot)23391da177e4SLinus Torvalds static int reiserfs_mark_dquot_dirty(struct dquot *dquot)
23401da177e4SLinus Torvalds {
23414506567bSJan Kara 	/* Are we journaling quotas? */
23421da177e4SLinus Torvalds 	if (REISERFS_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] ||
23431da177e4SLinus Torvalds 	    REISERFS_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) {
23441da177e4SLinus Torvalds 		dquot_mark_dquot_dirty(dquot);
23451da177e4SLinus Torvalds 		return reiserfs_write_dquot(dquot);
2346bd4c625cSLinus Torvalds 	} else
23471da177e4SLinus Torvalds 		return dquot_mark_dquot_dirty(dquot);
23481da177e4SLinus Torvalds }
23491da177e4SLinus Torvalds 
reiserfs_write_info(struct super_block * sb,int type)23501da177e4SLinus Torvalds static int reiserfs_write_info(struct super_block *sb, int type)
23511da177e4SLinus Torvalds {
23521da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
2353bd6a1f16SJan Kara 	int ret, err;
2354d2d0395fSJeff Mahoney 	int depth;
23551da177e4SLinus Torvalds 
23561da177e4SLinus Torvalds 	/* Data block + inode block */
23571da177e4SLinus Torvalds 	reiserfs_write_lock(sb);
2358bd6a1f16SJan Kara 	ret = journal_begin(&th, sb, 2);
2359bd6a1f16SJan Kara 	if (ret)
2360bd6a1f16SJan Kara 		goto out;
2361d2d0395fSJeff Mahoney 	depth = reiserfs_write_unlock_nested(sb);
23621da177e4SLinus Torvalds 	ret = dquot_commit_info(sb, type);
2363d2d0395fSJeff Mahoney 	reiserfs_write_lock_nested(sb, depth);
236458d85426SJeff Mahoney 	err = journal_end(&th);
2365bd6a1f16SJan Kara 	if (!ret && err)
2366bd6a1f16SJan Kara 		ret = err;
2367bd6a1f16SJan Kara out:
23681da177e4SLinus Torvalds 	reiserfs_write_unlock(sb);
23691da177e4SLinus Torvalds 	return ret;
23701da177e4SLinus Torvalds }
23711da177e4SLinus Torvalds 
23721da177e4SLinus Torvalds /*
237384de856eSChristoph Hellwig  * Turn on quotas during mount time - we need to find the quota file and such...
23741da177e4SLinus Torvalds  */
reiserfs_quota_on_mount(struct super_block * sb,int type)23751da177e4SLinus Torvalds static int reiserfs_quota_on_mount(struct super_block *sb, int type)
23761da177e4SLinus Torvalds {
2377287a8095SChristoph Hellwig 	return dquot_quota_on_mount(sb, REISERFS_SB(sb)->s_qf_names[type],
237884de856eSChristoph Hellwig 					REISERFS_SB(sb)->s_jquota_fmt, type);
23791da177e4SLinus Torvalds }
23801da177e4SLinus Torvalds 
23811da177e4SLinus Torvalds /*
23821da177e4SLinus Torvalds  * Standard function to be called on quota_on
23831da177e4SLinus Torvalds  */
reiserfs_quota_on(struct super_block * sb,int type,int format_id,const struct path * path)2384bd4c625cSLinus Torvalds static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
23858c54ca9cSAl Viro 			     const struct path *path)
23861da177e4SLinus Torvalds {
23871da177e4SLinus Torvalds 	int err;
2388d5dee5c3SJan Kara 	struct inode *inode;
23895d4f7fddSJan Kara 	struct reiserfs_transaction_handle th;
2390c3aa0776SJan Kara 	int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA;
23911da177e4SLinus Torvalds 
2392b9e06ef2SJan Kara 	reiserfs_write_lock(sb);
2393b9e06ef2SJan Kara 	if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) {
2394b9e06ef2SJan Kara 		err = -EINVAL;
2395b9e06ef2SJan Kara 		goto out;
2396b9e06ef2SJan Kara 	}
2397307ae18aSChristoph Hellwig 
23981da177e4SLinus Torvalds 	/* Quotafile not on the same filesystem? */
2399d8c9584eSAl Viro 	if (path->dentry->d_sb != sb) {
240077e69dacSAl Viro 		err = -EXDEV;
240177e69dacSAl Viro 		goto out;
24021da177e4SLinus Torvalds 	}
24032b0143b5SDavid Howells 	inode = d_inode(path->dentry);
2404098297b2SJeff Mahoney 	/*
2405098297b2SJeff Mahoney 	 * We must not pack tails for quota files on reiserfs for quota
2406098297b2SJeff Mahoney 	 * IO to work
2407098297b2SJeff Mahoney 	 */
2408d5dee5c3SJan Kara 	if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
240903eb6066SMiklos Szeredi 		err = reiserfs_unpack(inode);
2410d5dee5c3SJan Kara 		if (err) {
241145b03d5eSJeff Mahoney 			reiserfs_warning(sb, "super-6520",
241245b03d5eSJeff Mahoney 				"Unpacking tail of quota file failed"
2413d5dee5c3SJan Kara 				" (%d). Cannot turn on quotas.", err);
241477e69dacSAl Viro 			err = -EINVAL;
241577e69dacSAl Viro 			goto out;
24161da177e4SLinus Torvalds 		}
2417d5dee5c3SJan Kara 		mark_inode_dirty(inode);
2418d5dee5c3SJan Kara 	}
24195d4f7fddSJan Kara 	/* Journaling quota? */
24205d4f7fddSJan Kara 	if (REISERFS_SB(sb)->s_qf_names[type]) {
24211da177e4SLinus Torvalds 		/* Quotafile not of fs root? */
2422f00c9e44SJan Kara 		if (path->dentry->d_parent != sb->s_root)
242345b03d5eSJeff Mahoney 			reiserfs_warning(sb, "super-6521",
242445b03d5eSJeff Mahoney 				 "Quota file not on filesystem root. "
24251da177e4SLinus Torvalds 				 "Journalled quota will not work.");
24265d4f7fddSJan Kara 	}
24275d4f7fddSJan Kara 
24285d4f7fddSJan Kara 	/*
24295d4f7fddSJan Kara 	 * When we journal data on quota file, we have to flush journal to see
24305d4f7fddSJan Kara 	 * all updates to the file when we bypass pagecache...
24315d4f7fddSJan Kara 	 */
24325d4f7fddSJan Kara 	if (reiserfs_file_data_log(inode)) {
24335d4f7fddSJan Kara 		/* Just start temporary transaction and finish it */
24345d4f7fddSJan Kara 		err = journal_begin(&th, sb, 1);
24355d4f7fddSJan Kara 		if (err)
243677e69dacSAl Viro 			goto out;
243758d85426SJeff Mahoney 		err = journal_end_sync(&th);
24385d4f7fddSJan Kara 		if (err)
243977e69dacSAl Viro 			goto out;
24405d4f7fddSJan Kara 	}
2441b9e06ef2SJan Kara 	reiserfs_write_unlock(sb);
244233eb928aSJan Kara 	err = dquot_quota_on(sb, type, format_id, path);
244333eb928aSJan Kara 	if (!err) {
244433eb928aSJan Kara 		inode_lock(inode);
244533eb928aSJan Kara 		REISERFS_I(inode)->i_attrs |= REISERFS_IMMUTABLE_FL |
244633eb928aSJan Kara 					      REISERFS_NOATIME_FL;
244733eb928aSJan Kara 		inode_set_flags(inode, S_IMMUTABLE | S_NOATIME,
244833eb928aSJan Kara 				S_IMMUTABLE | S_NOATIME);
244933eb928aSJan Kara 		inode_unlock(inode);
245033eb928aSJan Kara 		mark_inode_dirty(inode);
245133eb928aSJan Kara 	}
245233eb928aSJan Kara 	return err;
245377e69dacSAl Viro out:
2454b9e06ef2SJan Kara 	reiserfs_write_unlock(sb);
245577e69dacSAl Viro 	return err;
24561da177e4SLinus Torvalds }
24571da177e4SLinus Torvalds 
reiserfs_quota_off(struct super_block * sb,int type)245833eb928aSJan Kara static int reiserfs_quota_off(struct super_block *sb, int type)
245933eb928aSJan Kara {
246033eb928aSJan Kara 	int err;
246133eb928aSJan Kara 	struct inode *inode = sb_dqopt(sb)->files[type];
246233eb928aSJan Kara 
246333eb928aSJan Kara 	if (!inode || !igrab(inode))
246433eb928aSJan Kara 		goto out;
246533eb928aSJan Kara 
246633eb928aSJan Kara 	err = dquot_quota_off(sb, type);
246733eb928aSJan Kara 	if (err)
246833eb928aSJan Kara 		goto out_put;
246933eb928aSJan Kara 
247033eb928aSJan Kara 	inode_lock(inode);
247133eb928aSJan Kara 	REISERFS_I(inode)->i_attrs &= ~(REISERFS_IMMUTABLE_FL |
247233eb928aSJan Kara 					REISERFS_NOATIME_FL);
247333eb928aSJan Kara 	inode_set_flags(inode, 0, S_IMMUTABLE | S_NOATIME);
247433eb928aSJan Kara 	inode_unlock(inode);
247533eb928aSJan Kara 	mark_inode_dirty(inode);
247633eb928aSJan Kara out_put:
247733eb928aSJan Kara 	iput(inode);
247833eb928aSJan Kara 	return err;
247933eb928aSJan Kara out:
248033eb928aSJan Kara 	return dquot_quota_off(sb, type);
248133eb928aSJan Kara }
248233eb928aSJan Kara 
2483098297b2SJeff Mahoney /*
2484098297b2SJeff Mahoney  * Read data from quotafile - avoid pagecache and such because we cannot afford
24851da177e4SLinus Torvalds  * acquiring the locks... As quota files are never truncated and quota code
24861da177e4SLinus Torvalds  * itself serializes the operations (and no one else should touch the files)
2487098297b2SJeff Mahoney  * we don't have to be afraid of races
2488098297b2SJeff Mahoney  */
reiserfs_quota_read(struct super_block * sb,int type,char * data,size_t len,loff_t off)24891da177e4SLinus Torvalds static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data,
24901da177e4SLinus Torvalds 				   size_t len, loff_t off)
24911da177e4SLinus Torvalds {
24921da177e4SLinus Torvalds 	struct inode *inode = sb_dqopt(sb)->files[type];
24931da177e4SLinus Torvalds 	unsigned long blk = off >> sb->s_blocksize_bits;
24941da177e4SLinus Torvalds 	int err = 0, offset = off & (sb->s_blocksize - 1), tocopy;
24951da177e4SLinus Torvalds 	size_t toread;
24961da177e4SLinus Torvalds 	struct buffer_head tmp_bh, *bh;
24971da177e4SLinus Torvalds 	loff_t i_size = i_size_read(inode);
24981da177e4SLinus Torvalds 
24991da177e4SLinus Torvalds 	if (off > i_size)
25001da177e4SLinus Torvalds 		return 0;
25011da177e4SLinus Torvalds 	if (off + len > i_size)
25021da177e4SLinus Torvalds 		len = i_size - off;
25031da177e4SLinus Torvalds 	toread = len;
25041da177e4SLinus Torvalds 	while (toread > 0) {
2505e03d3b1bSJiangshan Yi 		tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread);
25061da177e4SLinus Torvalds 		tmp_bh.b_state = 0;
2507098297b2SJeff Mahoney 		/*
2508098297b2SJeff Mahoney 		 * Quota files are without tails so we can safely
2509098297b2SJeff Mahoney 		 * use this function
2510098297b2SJeff Mahoney 		 */
25111da177e4SLinus Torvalds 		reiserfs_write_lock(sb);
25121da177e4SLinus Torvalds 		err = reiserfs_get_block(inode, blk, &tmp_bh, 0);
25131da177e4SLinus Torvalds 		reiserfs_write_unlock(sb);
25141da177e4SLinus Torvalds 		if (err)
25151da177e4SLinus Torvalds 			return err;
25161da177e4SLinus Torvalds 		if (!buffer_mapped(&tmp_bh))	/* A hole? */
25171da177e4SLinus Torvalds 			memset(data, 0, tocopy);
25181da177e4SLinus Torvalds 		else {
25191da177e4SLinus Torvalds 			bh = sb_bread(sb, tmp_bh.b_blocknr);
25201da177e4SLinus Torvalds 			if (!bh)
25211da177e4SLinus Torvalds 				return -EIO;
25221da177e4SLinus Torvalds 			memcpy(data, bh->b_data + offset, tocopy);
25231da177e4SLinus Torvalds 			brelse(bh);
25241da177e4SLinus Torvalds 		}
25251da177e4SLinus Torvalds 		offset = 0;
25261da177e4SLinus Torvalds 		toread -= tocopy;
25271da177e4SLinus Torvalds 		data += tocopy;
25281da177e4SLinus Torvalds 		blk++;
25291da177e4SLinus Torvalds 	}
25301da177e4SLinus Torvalds 	return len;
25311da177e4SLinus Torvalds }
25321da177e4SLinus Torvalds 
2533098297b2SJeff Mahoney /*
2534098297b2SJeff Mahoney  * Write to quotafile (we know the transaction is already started and has
2535098297b2SJeff Mahoney  * enough credits)
2536098297b2SJeff Mahoney  */
reiserfs_quota_write(struct super_block * sb,int type,const char * data,size_t len,loff_t off)25371da177e4SLinus Torvalds static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
25381da177e4SLinus Torvalds 				    const char *data, size_t len, loff_t off)
25391da177e4SLinus Torvalds {
25401da177e4SLinus Torvalds 	struct inode *inode = sb_dqopt(sb)->files[type];
25411da177e4SLinus Torvalds 	unsigned long blk = off >> sb->s_blocksize_bits;
25421da177e4SLinus Torvalds 	int err = 0, offset = off & (sb->s_blocksize - 1), tocopy;
25431da177e4SLinus Torvalds 	int journal_quota = REISERFS_SB(sb)->s_qf_names[type] != NULL;
25441da177e4SLinus Torvalds 	size_t towrite = len;
25451da177e4SLinus Torvalds 	struct buffer_head tmp_bh, *bh;
25461da177e4SLinus Torvalds 
25479c3013e9SJan Kara 	if (!current->journal_info) {
254853872ed0SFabian Frederick 		printk(KERN_WARNING "reiserfs: Quota write (off=%llu, len=%llu) cancelled because transaction is not started.\n",
25499c3013e9SJan Kara 			(unsigned long long)off, (unsigned long long)len);
25509c3013e9SJan Kara 		return -EIO;
25519c3013e9SJan Kara 	}
25521da177e4SLinus Torvalds 	while (towrite > 0) {
2553e03d3b1bSJiangshan Yi 		tocopy = min_t(unsigned long, sb->s_blocksize - offset, towrite);
25541da177e4SLinus Torvalds 		tmp_bh.b_state = 0;
2555361d94a3SJan Kara 		reiserfs_write_lock(sb);
25561da177e4SLinus Torvalds 		err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE);
2557361d94a3SJan Kara 		reiserfs_write_unlock(sb);
25581da177e4SLinus Torvalds 		if (err)
25591da177e4SLinus Torvalds 			goto out;
25601da177e4SLinus Torvalds 		if (offset || tocopy != sb->s_blocksize)
25611da177e4SLinus Torvalds 			bh = sb_bread(sb, tmp_bh.b_blocknr);
25621da177e4SLinus Torvalds 		else
25631da177e4SLinus Torvalds 			bh = sb_getblk(sb, tmp_bh.b_blocknr);
25641da177e4SLinus Torvalds 		if (!bh) {
25651da177e4SLinus Torvalds 			err = -EIO;
25661da177e4SLinus Torvalds 			goto out;
25671da177e4SLinus Torvalds 		}
25681da177e4SLinus Torvalds 		lock_buffer(bh);
25691da177e4SLinus Torvalds 		memcpy(bh->b_data + offset, data, tocopy);
25701da177e4SLinus Torvalds 		flush_dcache_page(bh->b_page);
25711da177e4SLinus Torvalds 		set_buffer_uptodate(bh);
25721da177e4SLinus Torvalds 		unlock_buffer(bh);
2573361d94a3SJan Kara 		reiserfs_write_lock(sb);
25741da177e4SLinus Torvalds 		reiserfs_prepare_for_journal(sb, bh, 1);
257509f1b80bSJeff Mahoney 		journal_mark_dirty(current->journal_info, bh);
25761da177e4SLinus Torvalds 		if (!journal_quota)
25771da177e4SLinus Torvalds 			reiserfs_add_ordered_list(inode, bh);
2578361d94a3SJan Kara 		reiserfs_write_unlock(sb);
25791da177e4SLinus Torvalds 		brelse(bh);
25801da177e4SLinus Torvalds 		offset = 0;
25811da177e4SLinus Torvalds 		towrite -= tocopy;
25821da177e4SLinus Torvalds 		data += tocopy;
25831da177e4SLinus Torvalds 		blk++;
25841da177e4SLinus Torvalds 	}
25851da177e4SLinus Torvalds out:
258667f1648dSJan Kara 	if (len == towrite)
25871da177e4SLinus Torvalds 		return err;
25881da177e4SLinus Torvalds 	if (inode->i_size < off + len - towrite)
25891da177e4SLinus Torvalds 		i_size_write(inode, off + len - towrite);
2590ae834901SJeff Layton 	inode->i_mtime = inode_set_ctime_current(inode);
25911da177e4SLinus Torvalds 	mark_inode_dirty(inode);
25921da177e4SLinus Torvalds 	return len - towrite;
25931da177e4SLinus Torvalds }
25941da177e4SLinus Torvalds 
25951da177e4SLinus Torvalds #endif
25961da177e4SLinus Torvalds 
get_super_block(struct file_system_type * fs_type,int flags,const char * dev_name,void * data)2597152a0836SAl Viro static struct dentry *get_super_block(struct file_system_type *fs_type,
2598bd4c625cSLinus Torvalds 			   int flags, const char *dev_name,
2599152a0836SAl Viro 			   void *data)
26001da177e4SLinus Torvalds {
2601152a0836SAl Viro 	return mount_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super);
26021da177e4SLinus Torvalds }
26031da177e4SLinus Torvalds 
init_reiserfs_fs(void)2604bd4c625cSLinus Torvalds static int __init init_reiserfs_fs(void)
26051da177e4SLinus Torvalds {
26061da177e4SLinus Torvalds 	int ret;
26071da177e4SLinus Torvalds 
2608797d9016SJeff Mahoney 	ret = init_inodecache();
2609797d9016SJeff Mahoney 	if (ret)
26101da177e4SLinus Torvalds 		return ret;
26111da177e4SLinus Torvalds 
26121da177e4SLinus Torvalds 	reiserfs_proc_info_global_init();
26131da177e4SLinus Torvalds 
26141da177e4SLinus Torvalds 	ret = register_filesystem(&reiserfs_fs_type);
2615797d9016SJeff Mahoney 	if (ret)
2616797d9016SJeff Mahoney 		goto out;
26171da177e4SLinus Torvalds 
26181da177e4SLinus Torvalds 	return 0;
2619797d9016SJeff Mahoney out:
26201da177e4SLinus Torvalds 	reiserfs_proc_info_global_done();
26211da177e4SLinus Torvalds 	destroy_inodecache();
26221da177e4SLinus Torvalds 
26231da177e4SLinus Torvalds 	return ret;
26241da177e4SLinus Torvalds }
26251da177e4SLinus Torvalds 
exit_reiserfs_fs(void)2626bd4c625cSLinus Torvalds static void __exit exit_reiserfs_fs(void)
26271da177e4SLinus Torvalds {
26281da177e4SLinus Torvalds 	reiserfs_proc_info_global_done();
26291da177e4SLinus Torvalds 	unregister_filesystem(&reiserfs_fs_type);
26301da177e4SLinus Torvalds 	destroy_inodecache();
26311da177e4SLinus Torvalds }
26321da177e4SLinus Torvalds 
26331da177e4SLinus Torvalds struct file_system_type reiserfs_fs_type = {
26341da177e4SLinus Torvalds 	.owner = THIS_MODULE,
26351da177e4SLinus Torvalds 	.name = "reiserfs",
2636152a0836SAl Viro 	.mount = get_super_block,
2637edc666e2SDavid Howells 	.kill_sb = reiserfs_kill_sb,
26381da177e4SLinus Torvalds 	.fs_flags = FS_REQUIRES_DEV,
26391da177e4SLinus Torvalds };
26407f78e035SEric W. Biederman MODULE_ALIAS_FS("reiserfs");
26411da177e4SLinus Torvalds 
26421da177e4SLinus Torvalds MODULE_DESCRIPTION("ReiserFS journaled filesystem");
26431da177e4SLinus Torvalds MODULE_AUTHOR("Hans Reiser <reiser@namesys.com>");
26441da177e4SLinus Torvalds MODULE_LICENSE("GPL");
26451da177e4SLinus Torvalds 
26461da177e4SLinus Torvalds module_init(init_reiserfs_fs);
26471da177e4SLinus Torvalds module_exit(exit_reiserfs_fs);
2648