xref: /openbmc/linux/fs/reiserfs/super.c (revision 3bb3e1fc)
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>
181da177e4SLinus Torvalds #include <asm/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>
241da177e4SLinus Torvalds #include <linux/buffer_head.h>
25a5694255SChristoph Hellwig #include <linux/exportfs.h>
2674abb989SJan Kara #include <linux/quotaops.h>
271da177e4SLinus Torvalds #include <linux/vfs.h>
281da177e4SLinus Torvalds #include <linux/mount.h>
291da177e4SLinus Torvalds #include <linux/namei.h>
30651d0623SColy Li #include <linux/crc32.h>
31c3aa0776SJan Kara #include <linux/seq_file.h>
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds struct file_system_type reiserfs_fs_type;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds static const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING;
361da177e4SLinus Torvalds static const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;
371da177e4SLinus Torvalds static const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds int is_reiserfs_3_5(struct reiserfs_super_block *rs)
401da177e4SLinus Torvalds {
411da177e4SLinus Torvalds 	return !strncmp(rs->s_v1.s_magic, reiserfs_3_5_magic_string,
421da177e4SLinus Torvalds 			strlen(reiserfs_3_5_magic_string));
431da177e4SLinus Torvalds }
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds int is_reiserfs_3_6(struct reiserfs_super_block *rs)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	return !strncmp(rs->s_v1.s_magic, reiserfs_3_6_magic_string,
481da177e4SLinus Torvalds 			strlen(reiserfs_3_6_magic_string));
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds int is_reiserfs_jr(struct reiserfs_super_block *rs)
521da177e4SLinus Torvalds {
531da177e4SLinus Torvalds 	return !strncmp(rs->s_v1.s_magic, reiserfs_jr_magic_string,
541da177e4SLinus Torvalds 			strlen(reiserfs_jr_magic_string));
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds 	return (is_reiserfs_3_5(rs) || is_reiserfs_3_6(rs) ||
601da177e4SLinus Torvalds 		is_reiserfs_jr(rs));
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds static int reiserfs_remount(struct super_block *s, int *flags, char *data);
64726c3342SDavid Howells static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf);
65c3aa0776SJan Kara void show_alloc_options(struct seq_file *seq, struct super_block *s);
661da177e4SLinus Torvalds 
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))
781da177e4SLinus Torvalds 		if (!journal_end_sync(&th, s, 1))
791da177e4SLinus Torvalds 			reiserfs_flush_old_commits(s);
801da177e4SLinus Torvalds 	reiserfs_write_unlock(s);
811da177e4SLinus Torvalds 	return 0;
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds 
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 
92033369d1SArtem Bityutskiy 	spin_lock(&sbi->old_work_lock);
93033369d1SArtem Bityutskiy 	sbi->work_queued = 0;
94033369d1SArtem Bityutskiy 	spin_unlock(&sbi->old_work_lock);
95033369d1SArtem Bityutskiy 
961da177e4SLinus Torvalds 	reiserfs_sync_fs(s, 1);
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
99033369d1SArtem Bityutskiy void reiserfs_schedule_old_flush(struct super_block *s)
100033369d1SArtem Bityutskiy {
101033369d1SArtem Bityutskiy 	struct reiserfs_sb_info *sbi = REISERFS_SB(s);
102033369d1SArtem Bityutskiy 	unsigned long delay;
103033369d1SArtem Bityutskiy 
104033369d1SArtem Bityutskiy 	if (s->s_flags & MS_RDONLY)
105033369d1SArtem Bityutskiy 		return;
106033369d1SArtem Bityutskiy 
107033369d1SArtem Bityutskiy 	spin_lock(&sbi->old_work_lock);
108033369d1SArtem Bityutskiy 	if (!sbi->work_queued) {
109033369d1SArtem Bityutskiy 		delay = msecs_to_jiffies(dirty_writeback_interval * 10);
110033369d1SArtem Bityutskiy 		queue_delayed_work(system_long_wq, &sbi->old_work, delay);
111033369d1SArtem Bityutskiy 		sbi->work_queued = 1;
112033369d1SArtem Bityutskiy 	}
113033369d1SArtem Bityutskiy 	spin_unlock(&sbi->old_work_lock);
114033369d1SArtem Bityutskiy }
115033369d1SArtem Bityutskiy 
116033369d1SArtem Bityutskiy static void cancel_old_flush(struct super_block *s)
117033369d1SArtem Bityutskiy {
118033369d1SArtem Bityutskiy 	struct reiserfs_sb_info *sbi = REISERFS_SB(s);
119033369d1SArtem Bityutskiy 
120033369d1SArtem Bityutskiy 	cancel_delayed_work_sync(&REISERFS_SB(s)->old_work);
121033369d1SArtem Bityutskiy 	spin_lock(&sbi->old_work_lock);
122033369d1SArtem Bityutskiy 	sbi->work_queued = 0;
123033369d1SArtem Bityutskiy 	spin_unlock(&sbi->old_work_lock);
124033369d1SArtem Bityutskiy }
125033369d1SArtem Bityutskiy 
126c4be0c1dSTakashi Sato static int reiserfs_freeze(struct super_block *s)
1271da177e4SLinus Torvalds {
1281da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
129033369d1SArtem Bityutskiy 
130033369d1SArtem Bityutskiy 	cancel_old_flush(s);
131033369d1SArtem Bityutskiy 
1321da177e4SLinus Torvalds 	reiserfs_write_lock(s);
1331da177e4SLinus Torvalds 	if (!(s->s_flags & MS_RDONLY)) {
1341da177e4SLinus Torvalds 		int err = journal_begin(&th, s, 1);
1351da177e4SLinus Torvalds 		if (err) {
1361da177e4SLinus Torvalds 			reiserfs_block_writes(&th);
1371da177e4SLinus Torvalds 		} else {
138bd4c625cSLinus Torvalds 			reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
139bd4c625cSLinus Torvalds 						     1);
1401da177e4SLinus Torvalds 			journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
1411da177e4SLinus Torvalds 			reiserfs_block_writes(&th);
1421da177e4SLinus Torvalds 			journal_end_sync(&th, s, 1);
1431da177e4SLinus Torvalds 		}
1441da177e4SLinus Torvalds 	}
1451da177e4SLinus Torvalds 	reiserfs_write_unlock(s);
146c4be0c1dSTakashi Sato 	return 0;
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds 
149c4be0c1dSTakashi Sato static int reiserfs_unfreeze(struct super_block *s)
150bd4c625cSLinus Torvalds {
1511da177e4SLinus Torvalds 	reiserfs_allow_writes(s);
152c4be0c1dSTakashi Sato 	return 0;
1531da177e4SLinus Torvalds }
1541da177e4SLinus Torvalds 
1556a3a16f2SAl Viro extern const struct in_core_key MAX_IN_CORE_KEY;
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds /* this is used to delete "save link" when there are no items of a
1581da177e4SLinus Torvalds    file it points to. It can either happen if unlink is completed but
1591da177e4SLinus Torvalds    "save unlink" removal, or if file has both unlink and truncate
1601da177e4SLinus Torvalds    pending and as unlink completes first (because key of "save link"
1611da177e4SLinus Torvalds    protecting unlink is bigger that a key lf "save link" which
1621da177e4SLinus Torvalds    protects truncate), so there left no items to make truncate
1631da177e4SLinus Torvalds    completion on */
164bd4c625cSLinus Torvalds static int remove_save_link_only(struct super_block *s,
165bd4c625cSLinus Torvalds 				 struct reiserfs_key *key, int oid_free)
1661da177e4SLinus Torvalds {
1671da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
1681da177e4SLinus Torvalds 	int err;
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 	/* we are going to do one balancing */
1711da177e4SLinus Torvalds 	err = journal_begin(&th, s, JOURNAL_PER_BALANCE_CNT);
1721da177e4SLinus Torvalds 	if (err)
1731da177e4SLinus Torvalds 		return err;
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	reiserfs_delete_solid_item(&th, NULL, key);
1761da177e4SLinus Torvalds 	if (oid_free)
1771da177e4SLinus Torvalds 		/* removals are protected by direct items */
1781da177e4SLinus Torvalds 		reiserfs_release_objectid(&th, le32_to_cpu(key->k_objectid));
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	return journal_end(&th, s, JOURNAL_PER_BALANCE_CNT);
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
1841da177e4SLinus Torvalds static int reiserfs_quota_on_mount(struct super_block *, int);
1851da177e4SLinus Torvalds #endif
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds /* look for uncompleted unlinks and truncates and complete them */
1881da177e4SLinus Torvalds static int finish_unfinished(struct super_block *s)
1891da177e4SLinus Torvalds {
1901da177e4SLinus Torvalds 	INITIALIZE_PATH(path);
1911da177e4SLinus Torvalds 	struct cpu_key max_cpu_key, obj_key;
192fb46f341SLepton Wu 	struct reiserfs_key save_link_key, last_inode_key;
1931da177e4SLinus Torvalds 	int retval = 0;
1941da177e4SLinus Torvalds 	struct item_head *ih;
1951da177e4SLinus Torvalds 	struct buffer_head *bh;
1961da177e4SLinus Torvalds 	int item_pos;
1971da177e4SLinus Torvalds 	char *item;
1981da177e4SLinus Torvalds 	int done;
1991da177e4SLinus Torvalds 	struct inode *inode;
2001da177e4SLinus Torvalds 	int truncate;
2011da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
2021da177e4SLinus Torvalds 	int i;
2031da177e4SLinus Torvalds 	int ms_active_set;
204f4b113aeSJan Kara 	int quota_enabled[MAXQUOTAS];
2051da177e4SLinus Torvalds #endif
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	/* compose key to look for "save" links */
2081da177e4SLinus Torvalds 	max_cpu_key.version = KEY_FORMAT_3_5;
209f359b74cSVladimir Saveliev 	max_cpu_key.on_disk_key.k_dir_id = ~0U;
210f359b74cSVladimir Saveliev 	max_cpu_key.on_disk_key.k_objectid = ~0U;
211f359b74cSVladimir Saveliev 	set_cpu_key_k_offset(&max_cpu_key, ~0U);
2121da177e4SLinus Torvalds 	max_cpu_key.key_length = 3;
2131da177e4SLinus Torvalds 
214fb46f341SLepton Wu 	memset(&last_inode_key, 0, sizeof(last_inode_key));
215fb46f341SLepton Wu 
2161da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
2171da177e4SLinus Torvalds 	/* Needed for iput() to work correctly and not trash data */
2181da177e4SLinus Torvalds 	if (s->s_flags & MS_ACTIVE) {
2191da177e4SLinus Torvalds 		ms_active_set = 0;
2201da177e4SLinus Torvalds 	} else {
2211da177e4SLinus Torvalds 		ms_active_set = 1;
2221da177e4SLinus Torvalds 		s->s_flags |= MS_ACTIVE;
2231da177e4SLinus Torvalds 	}
2241da177e4SLinus Torvalds 	/* Turn on quotas so that they are updated correctly */
2251da177e4SLinus Torvalds 	for (i = 0; i < MAXQUOTAS; i++) {
226f4b113aeSJan Kara 		quota_enabled[i] = 1;
2271da177e4SLinus Torvalds 		if (REISERFS_SB(s)->s_qf_names[i]) {
228f4b113aeSJan Kara 			int ret;
229f4b113aeSJan Kara 
230f4b113aeSJan Kara 			if (sb_has_quota_active(s, i)) {
231f4b113aeSJan Kara 				quota_enabled[i] = 0;
232f4b113aeSJan Kara 				continue;
233f4b113aeSJan Kara 			}
234f4b113aeSJan Kara 			ret = reiserfs_quota_on_mount(s, i);
2351da177e4SLinus Torvalds 			if (ret < 0)
23645b03d5eSJeff Mahoney 				reiserfs_warning(s, "reiserfs-2500",
23745b03d5eSJeff Mahoney 						 "cannot turn on journaled "
23845b03d5eSJeff Mahoney 						 "quota: error %d", ret);
2391da177e4SLinus Torvalds 		}
2401da177e4SLinus Torvalds 	}
2411da177e4SLinus Torvalds #endif
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 	done = 0;
2441da177e4SLinus Torvalds 	REISERFS_SB(s)->s_is_unlinked_ok = 1;
2451da177e4SLinus Torvalds 	while (!retval) {
2461da177e4SLinus Torvalds 		retval = search_item(s, &max_cpu_key, &path);
2471da177e4SLinus Torvalds 		if (retval != ITEM_NOT_FOUND) {
2480030b645SJeff Mahoney 			reiserfs_error(s, "vs-2140",
2490030b645SJeff Mahoney 				       "search_by_key returned %d", retval);
2501da177e4SLinus Torvalds 			break;
2511da177e4SLinus Torvalds 		}
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 		bh = get_last_bh(&path);
2541da177e4SLinus Torvalds 		item_pos = get_item_pos(&path);
2551da177e4SLinus Torvalds 		if (item_pos != B_NR_ITEMS(bh)) {
25645b03d5eSJeff Mahoney 			reiserfs_warning(s, "vs-2060",
25745b03d5eSJeff Mahoney 					 "wrong position found");
2581da177e4SLinus Torvalds 			break;
2591da177e4SLinus Torvalds 		}
2601da177e4SLinus Torvalds 		item_pos--;
2611da177e4SLinus Torvalds 		ih = B_N_PITEM_HEAD(bh, item_pos);
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 		if (le32_to_cpu(ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID)
2641da177e4SLinus Torvalds 			/* there are no "save" links anymore */
2651da177e4SLinus Torvalds 			break;
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 		save_link_key = ih->ih_key;
2681da177e4SLinus Torvalds 		if (is_indirect_le_ih(ih))
2691da177e4SLinus Torvalds 			truncate = 1;
2701da177e4SLinus Torvalds 		else
2711da177e4SLinus Torvalds 			truncate = 0;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 		/* reiserfs_iget needs k_dirid and k_objectid only */
2741da177e4SLinus Torvalds 		item = B_I_PITEM(bh, ih);
2753e8962beSAl Viro 		obj_key.on_disk_key.k_dir_id = le32_to_cpu(*(__le32 *) item);
276bd4c625cSLinus Torvalds 		obj_key.on_disk_key.k_objectid =
277bd4c625cSLinus Torvalds 		    le32_to_cpu(ih->ih_key.k_objectid);
2786b9f5829SAl Viro 		obj_key.on_disk_key.k_offset = 0;
2796b9f5829SAl Viro 		obj_key.on_disk_key.k_type = 0;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 		pathrelse(&path);
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 		inode = reiserfs_iget(s, &obj_key);
2841da177e4SLinus Torvalds 		if (!inode) {
2851da177e4SLinus Torvalds 			/* the unlink almost completed, it just did not manage to remove
2861da177e4SLinus Torvalds 			   "save" link and release objectid */
28745b03d5eSJeff Mahoney 			reiserfs_warning(s, "vs-2180", "iget failed for %K",
2881da177e4SLinus Torvalds 					 &obj_key);
2891da177e4SLinus Torvalds 			retval = remove_save_link_only(s, &save_link_key, 1);
2901da177e4SLinus Torvalds 			continue;
2911da177e4SLinus Torvalds 		}
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 		if (!truncate && inode->i_nlink) {
2941da177e4SLinus Torvalds 			/* file is not unlinked */
29545b03d5eSJeff Mahoney 			reiserfs_warning(s, "vs-2185",
29645b03d5eSJeff Mahoney 					 "file %K is not unlinked",
2971da177e4SLinus Torvalds 					 &obj_key);
2981da177e4SLinus Torvalds 			retval = remove_save_link_only(s, &save_link_key, 0);
2991da177e4SLinus Torvalds 			continue;
3001da177e4SLinus Torvalds 		}
301871a2931SChristoph Hellwig 		dquot_initialize(inode);
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 		if (truncate && S_ISDIR(inode->i_mode)) {
3041da177e4SLinus Torvalds 			/* We got a truncate request for a dir which is impossible.
3051da177e4SLinus Torvalds 			   The only imaginable way is to execute unfinished truncate request
3061da177e4SLinus Torvalds 			   then boot into old kernel, remove the file and create dir with
3071da177e4SLinus Torvalds 			   the same key. */
30845b03d5eSJeff Mahoney 			reiserfs_warning(s, "green-2101",
30945b03d5eSJeff Mahoney 					 "impossible truncate on a "
31045b03d5eSJeff Mahoney 					 "directory %k. Please report",
311bd4c625cSLinus Torvalds 					 INODE_PKEY(inode));
3121da177e4SLinus Torvalds 			retval = remove_save_link_only(s, &save_link_key, 0);
3131da177e4SLinus Torvalds 			truncate = 0;
3141da177e4SLinus Torvalds 			iput(inode);
3151da177e4SLinus Torvalds 			continue;
3161da177e4SLinus Torvalds 		}
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 		if (truncate) {
319bd4c625cSLinus Torvalds 			REISERFS_I(inode)->i_flags |=
320bd4c625cSLinus Torvalds 			    i_link_saved_truncate_mask;
3211da177e4SLinus Torvalds 			/* not completed truncate found. New size was committed together
3221da177e4SLinus Torvalds 			   with "save" link */
3231da177e4SLinus Torvalds 			reiserfs_info(s, "Truncating %k to %Ld ..",
3241da177e4SLinus Torvalds 				      INODE_PKEY(inode), inode->i_size);
325bd4c625cSLinus Torvalds 			reiserfs_truncate_file(inode,
326bd4c625cSLinus Torvalds 					       0
327bd4c625cSLinus Torvalds 					       /*don't update modification time */
328bd4c625cSLinus Torvalds 					       );
3291da177e4SLinus Torvalds 			retval = remove_save_link(inode, truncate);
3301da177e4SLinus Torvalds 		} else {
3311da177e4SLinus Torvalds 			REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
3321da177e4SLinus Torvalds 			/* not completed unlink (rmdir) found */
3331da177e4SLinus Torvalds 			reiserfs_info(s, "Removing %k..", INODE_PKEY(inode));
334fb46f341SLepton Wu 			if (memcmp(&last_inode_key, INODE_PKEY(inode),
335fb46f341SLepton Wu 					sizeof(last_inode_key))){
336fb46f341SLepton Wu 				last_inode_key = *INODE_PKEY(inode);
3371da177e4SLinus Torvalds 				/* removal gets completed in iput */
3381da177e4SLinus Torvalds 				retval = 0;
339fb46f341SLepton Wu 			} else {
34045b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-2189", "Dead loop "
34145b03d5eSJeff Mahoney 						 "in finish_unfinished "
34245b03d5eSJeff Mahoney 						 "detected, just remove "
34345b03d5eSJeff Mahoney 						 "save link\n");
344fb46f341SLepton Wu 				retval = remove_save_link_only(s,
345fb46f341SLepton Wu 							&save_link_key, 0);
346fb46f341SLepton Wu 			}
3471da177e4SLinus Torvalds 		}
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 		iput(inode);
3501da177e4SLinus Torvalds 		printk("done\n");
3511da177e4SLinus Torvalds 		done++;
3521da177e4SLinus Torvalds 	}
3531da177e4SLinus Torvalds 	REISERFS_SB(s)->s_is_unlinked_ok = 0;
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
3561da177e4SLinus Torvalds 	/* Turn quotas off */
3571da177e4SLinus Torvalds 	for (i = 0; i < MAXQUOTAS; i++) {
358f4b113aeSJan Kara 		if (sb_dqopt(s)->files[i] && quota_enabled[i])
359287a8095SChristoph Hellwig 			dquot_quota_off(s, i);
3601da177e4SLinus Torvalds 	}
3611da177e4SLinus Torvalds 	if (ms_active_set)
3621da177e4SLinus Torvalds 		/* Restore the flag back */
3631da177e4SLinus Torvalds 		s->s_flags &= ~MS_ACTIVE;
3641da177e4SLinus Torvalds #endif
3651da177e4SLinus Torvalds 	pathrelse(&path);
3661da177e4SLinus Torvalds 	if (done)
3671da177e4SLinus Torvalds 		reiserfs_info(s, "There were %d uncompleted unlinks/truncates. "
3681da177e4SLinus Torvalds 			      "Completed\n", done);
3691da177e4SLinus Torvalds 	return retval;
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds /* to protect file being unlinked from getting lost we "safe" link files
3731da177e4SLinus Torvalds    being unlinked. This link will be deleted in the same transaction with last
3743a4fa0a2SRobert P. J. Day    item of file. mounting the filesystem we scan all these links and remove
3751da177e4SLinus Torvalds    files which almost got lost */
3761da177e4SLinus Torvalds void add_save_link(struct reiserfs_transaction_handle *th,
3771da177e4SLinus Torvalds 		   struct inode *inode, int truncate)
3781da177e4SLinus Torvalds {
3791da177e4SLinus Torvalds 	INITIALIZE_PATH(path);
3801da177e4SLinus Torvalds 	int retval;
3811da177e4SLinus Torvalds 	struct cpu_key key;
3821da177e4SLinus Torvalds 	struct item_head ih;
3833e8962beSAl Viro 	__le32 link;
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	BUG_ON(!th->t_trans_id);
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 	/* file can only get one "save link" of each kind */
3881da177e4SLinus Torvalds 	RFALSE(truncate &&
3891da177e4SLinus Torvalds 	       (REISERFS_I(inode)->i_flags & i_link_saved_truncate_mask),
3901da177e4SLinus Torvalds 	       "saved link already exists for truncated inode %lx",
3911da177e4SLinus Torvalds 	       (long)inode->i_ino);
3921da177e4SLinus Torvalds 	RFALSE(!truncate &&
3931da177e4SLinus Torvalds 	       (REISERFS_I(inode)->i_flags & i_link_saved_unlink_mask),
3941da177e4SLinus Torvalds 	       "saved link already exists for unlinked inode %lx",
3951da177e4SLinus Torvalds 	       (long)inode->i_ino);
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds 	/* setup key of "save" link */
3981da177e4SLinus Torvalds 	key.version = KEY_FORMAT_3_5;
3991da177e4SLinus Torvalds 	key.on_disk_key.k_dir_id = MAX_KEY_OBJECTID;
4001da177e4SLinus Torvalds 	key.on_disk_key.k_objectid = inode->i_ino;
4011da177e4SLinus Torvalds 	if (!truncate) {
4021da177e4SLinus Torvalds 		/* unlink, rmdir, rename */
4031da177e4SLinus Torvalds 		set_cpu_key_k_offset(&key, 1 + inode->i_sb->s_blocksize);
4041da177e4SLinus Torvalds 		set_cpu_key_k_type(&key, TYPE_DIRECT);
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 		/* item head of "safe" link */
407bd4c625cSLinus Torvalds 		make_le_item_head(&ih, &key, key.version,
408bd4c625cSLinus Torvalds 				  1 + inode->i_sb->s_blocksize, TYPE_DIRECT,
4091da177e4SLinus Torvalds 				  4 /*length */ , 0xffff /*free space */ );
4101da177e4SLinus Torvalds 	} else {
4111da177e4SLinus Torvalds 		/* truncate */
4121da177e4SLinus Torvalds 		if (S_ISDIR(inode->i_mode))
41345b03d5eSJeff Mahoney 			reiserfs_warning(inode->i_sb, "green-2102",
41445b03d5eSJeff Mahoney 					 "Adding a truncate savelink for "
41545b03d5eSJeff Mahoney 					 "a directory %k! Please report",
416bd4c625cSLinus Torvalds 					 INODE_PKEY(inode));
4171da177e4SLinus Torvalds 		set_cpu_key_k_offset(&key, 1);
4181da177e4SLinus Torvalds 		set_cpu_key_k_type(&key, TYPE_INDIRECT);
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 		/* item head of "safe" link */
4211da177e4SLinus Torvalds 		make_le_item_head(&ih, &key, key.version, 1, TYPE_INDIRECT,
4221da177e4SLinus Torvalds 				  4 /*length */ , 0 /*free space */ );
4231da177e4SLinus Torvalds 	}
4241da177e4SLinus Torvalds 	key.key_length = 3;
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	/* look for its place in the tree */
4271da177e4SLinus Torvalds 	retval = search_item(inode->i_sb, &key, &path);
4281da177e4SLinus Torvalds 	if (retval != ITEM_NOT_FOUND) {
4291da177e4SLinus Torvalds 		if (retval != -ENOSPC)
4300030b645SJeff Mahoney 			reiserfs_error(inode->i_sb, "vs-2100",
431bd4c625cSLinus Torvalds 				       "search_by_key (%K) returned %d", &key,
432bd4c625cSLinus Torvalds 				       retval);
4331da177e4SLinus Torvalds 		pathrelse(&path);
4341da177e4SLinus Torvalds 		return;
4351da177e4SLinus Torvalds 	}
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds 	/* body of "save" link */
4381da177e4SLinus Torvalds 	link = INODE_PKEY(inode)->k_dir_id;
4391da177e4SLinus Torvalds 
44025985edcSLucas De Marchi 	/* put "save" link into tree, don't charge quota to anyone */
441bd4c625cSLinus Torvalds 	retval =
442bd4c625cSLinus Torvalds 	    reiserfs_insert_item(th, &path, &key, &ih, NULL, (char *)&link);
4431da177e4SLinus Torvalds 	if (retval) {
4441da177e4SLinus Torvalds 		if (retval != -ENOSPC)
4450030b645SJeff Mahoney 			reiserfs_error(inode->i_sb, "vs-2120",
44645b03d5eSJeff Mahoney 				       "insert_item returned %d", retval);
4471da177e4SLinus Torvalds 	} else {
4481da177e4SLinus Torvalds 		if (truncate)
449bd4c625cSLinus Torvalds 			REISERFS_I(inode)->i_flags |=
450bd4c625cSLinus Torvalds 			    i_link_saved_truncate_mask;
4511da177e4SLinus Torvalds 		else
4521da177e4SLinus Torvalds 			REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
4531da177e4SLinus Torvalds 	}
4541da177e4SLinus Torvalds }
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds /* this opens transaction unlike add_save_link */
4571da177e4SLinus Torvalds int remove_save_link(struct inode *inode, int truncate)
4581da177e4SLinus Torvalds {
4591da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
4601da177e4SLinus Torvalds 	struct reiserfs_key key;
4611da177e4SLinus Torvalds 	int err;
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	/* we are going to do one balancing only */
4641da177e4SLinus Torvalds 	err = journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
4651da177e4SLinus Torvalds 	if (err)
4661da177e4SLinus Torvalds 		return err;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	/* setup key of "save" link */
4691da177e4SLinus Torvalds 	key.k_dir_id = cpu_to_le32(MAX_KEY_OBJECTID);
4701da177e4SLinus Torvalds 	key.k_objectid = INODE_PKEY(inode)->k_objectid;
4711da177e4SLinus Torvalds 	if (!truncate) {
4721da177e4SLinus Torvalds 		/* unlink, rmdir, rename */
4731da177e4SLinus Torvalds 		set_le_key_k_offset(KEY_FORMAT_3_5, &key,
4741da177e4SLinus Torvalds 				    1 + inode->i_sb->s_blocksize);
4751da177e4SLinus Torvalds 		set_le_key_k_type(KEY_FORMAT_3_5, &key, TYPE_DIRECT);
4761da177e4SLinus Torvalds 	} else {
4771da177e4SLinus Torvalds 		/* truncate */
4781da177e4SLinus Torvalds 		set_le_key_k_offset(KEY_FORMAT_3_5, &key, 1);
4791da177e4SLinus Torvalds 		set_le_key_k_type(KEY_FORMAT_3_5, &key, TYPE_INDIRECT);
4801da177e4SLinus Torvalds 	}
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds 	if ((truncate &&
4831da177e4SLinus Torvalds 	     (REISERFS_I(inode)->i_flags & i_link_saved_truncate_mask)) ||
4841da177e4SLinus Torvalds 	    (!truncate &&
4851da177e4SLinus Torvalds 	     (REISERFS_I(inode)->i_flags & i_link_saved_unlink_mask)))
4861da177e4SLinus Torvalds 		/* don't take quota bytes from anywhere */
4871da177e4SLinus Torvalds 		reiserfs_delete_solid_item(&th, NULL, &key);
4881da177e4SLinus Torvalds 	if (!truncate) {
4891da177e4SLinus Torvalds 		reiserfs_release_objectid(&th, inode->i_ino);
4901da177e4SLinus Torvalds 		REISERFS_I(inode)->i_flags &= ~i_link_saved_unlink_mask;
4911da177e4SLinus Torvalds 	} else
4921da177e4SLinus Torvalds 		REISERFS_I(inode)->i_flags &= ~i_link_saved_truncate_mask;
4931da177e4SLinus Torvalds 
4941da177e4SLinus Torvalds 	return journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
4951da177e4SLinus Torvalds }
4961da177e4SLinus Torvalds 
497edc666e2SDavid Howells static void reiserfs_kill_sb(struct super_block *s)
4981da177e4SLinus Torvalds {
499edc666e2SDavid Howells 	if (REISERFS_SB(s)) {
500a9e36da6SJeff Mahoney 		/*
501a9e36da6SJeff Mahoney 		 * Force any pending inode evictions to occur now. Any
502a9e36da6SJeff Mahoney 		 * inodes to be removed that have extended attributes
503a9e36da6SJeff Mahoney 		 * associated with them need to clean them up before
504a9e36da6SJeff Mahoney 		 * we can release the extended attribute root dentries.
505a9e36da6SJeff Mahoney 		 * shrink_dcache_for_umount will BUG if we don't release
506a9e36da6SJeff Mahoney 		 * those before it's called so ->put_super is too late.
507a9e36da6SJeff Mahoney 		 */
508a9e36da6SJeff Mahoney 		shrink_dcache_sb(s);
509a9e36da6SJeff Mahoney 
5101da177e4SLinus Torvalds 		dput(REISERFS_SB(s)->xattr_root);
511edc666e2SDavid Howells 		REISERFS_SB(s)->xattr_root = NULL;
5121da177e4SLinus Torvalds 		dput(REISERFS_SB(s)->priv_root);
513edc666e2SDavid Howells 		REISERFS_SB(s)->priv_root = NULL;
5141da177e4SLinus Torvalds 	}
515edc666e2SDavid Howells 
516edc666e2SDavid Howells 	kill_block_super(s);
517edc666e2SDavid Howells }
518edc666e2SDavid Howells 
519edc666e2SDavid Howells static void reiserfs_put_super(struct super_block *s)
520edc666e2SDavid Howells {
521edc666e2SDavid Howells 	struct reiserfs_transaction_handle th;
522edc666e2SDavid Howells 	th.t_trans_id = 0;
5231da177e4SLinus Torvalds 
524e0ccfd95SChristoph Hellwig 	dquot_disable(s, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
525e0ccfd95SChristoph Hellwig 
5268ebc4232SFrederic Weisbecker 	reiserfs_write_lock(s);
5276cfd0148SChristoph Hellwig 
5281da177e4SLinus Torvalds 	/* change file system state to current state if it was mounted with read-write permissions */
5291da177e4SLinus Torvalds 	if (!(s->s_flags & MS_RDONLY)) {
5301da177e4SLinus Torvalds 		if (!journal_begin(&th, s, 10)) {
531bd4c625cSLinus Torvalds 			reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
532bd4c625cSLinus Torvalds 						     1);
533bd4c625cSLinus Torvalds 			set_sb_umount_state(SB_DISK_SUPER_BLOCK(s),
534bd4c625cSLinus Torvalds 					    REISERFS_SB(s)->s_mount_state);
5351da177e4SLinus Torvalds 			journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
5361da177e4SLinus Torvalds 		}
5371da177e4SLinus Torvalds 	}
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds 	/* note, journal_release checks for readonly mount, and can decide not
5401da177e4SLinus Torvalds 	 ** to do a journal_end
5411da177e4SLinus Torvalds 	 */
5421da177e4SLinus Torvalds 	journal_release(&th, s);
5431da177e4SLinus Torvalds 
5445065227bSJeff Mahoney 	reiserfs_free_bitmap_cache(s);
5451da177e4SLinus Torvalds 
5461da177e4SLinus Torvalds 	brelse(SB_BUFFER_WITH_SB(s));
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	print_statistics(s);
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	if (REISERFS_SB(s)->reserved_blocks != 0) {
55145b03d5eSJeff Mahoney 		reiserfs_warning(s, "green-2005", "reserved blocks left %d",
5521da177e4SLinus Torvalds 				 REISERFS_SB(s)->reserved_blocks);
5531da177e4SLinus Torvalds 	}
5541da177e4SLinus Torvalds 
5551da177e4SLinus Torvalds 	reiserfs_proc_info_done(s);
5561da177e4SLinus Torvalds 
5578ebc4232SFrederic Weisbecker 	reiserfs_write_unlock(s);
5588ebc4232SFrederic Weisbecker 	mutex_destroy(&REISERFS_SB(s)->lock);
5591da177e4SLinus Torvalds 	kfree(s->s_fs_info);
5601da177e4SLinus Torvalds 	s->s_fs_info = NULL;
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds 
563e18b890bSChristoph Lameter static struct kmem_cache *reiserfs_inode_cachep;
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds static struct inode *reiserfs_alloc_inode(struct super_block *sb)
5661da177e4SLinus Torvalds {
5671da177e4SLinus Torvalds 	struct reiserfs_inode_info *ei;
568bd4c625cSLinus Torvalds 	ei = (struct reiserfs_inode_info *)
569e94b1766SChristoph Lameter 	    kmem_cache_alloc(reiserfs_inode_cachep, GFP_KERNEL);
5701da177e4SLinus Torvalds 	if (!ei)
5711da177e4SLinus Torvalds 		return NULL;
5720e4f6a79SAl Viro 	atomic_set(&ei->openers, 0);
5730e4f6a79SAl Viro 	mutex_init(&ei->tailpack);
5741da177e4SLinus Torvalds 	return &ei->vfs_inode;
5751da177e4SLinus Torvalds }
5761da177e4SLinus Torvalds 
577fa0d7e3dSNick Piggin static void reiserfs_i_callback(struct rcu_head *head)
578fa0d7e3dSNick Piggin {
579fa0d7e3dSNick Piggin 	struct inode *inode = container_of(head, struct inode, i_rcu);
580fa0d7e3dSNick Piggin 	kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));
581fa0d7e3dSNick Piggin }
582fa0d7e3dSNick Piggin 
5831da177e4SLinus Torvalds static void reiserfs_destroy_inode(struct inode *inode)
5841da177e4SLinus Torvalds {
585fa0d7e3dSNick Piggin 	call_rcu(&inode->i_rcu, reiserfs_i_callback);
5861da177e4SLinus Torvalds }
5871da177e4SLinus Torvalds 
58851cc5068SAlexey Dobriyan static void init_once(void *foo)
5891da177e4SLinus Torvalds {
5901da177e4SLinus Torvalds 	struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo;
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 	INIT_LIST_HEAD(&ei->i_prealloc_list);
5931da177e4SLinus Torvalds 	inode_init_once(&ei->vfs_inode);
5941da177e4SLinus Torvalds }
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds static int init_inodecache(void)
5971da177e4SLinus Torvalds {
5981da177e4SLinus Torvalds 	reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache",
599bd4c625cSLinus Torvalds 						  sizeof(struct
600bd4c625cSLinus Torvalds 							 reiserfs_inode_info),
601fffb60f9SPaul Jackson 						  0, (SLAB_RECLAIM_ACCOUNT|
602fffb60f9SPaul Jackson 							SLAB_MEM_SPREAD),
60320c2df83SPaul Mundt 						  init_once);
6041da177e4SLinus Torvalds 	if (reiserfs_inode_cachep == NULL)
6051da177e4SLinus Torvalds 		return -ENOMEM;
6061da177e4SLinus Torvalds 	return 0;
6071da177e4SLinus Torvalds }
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds static void destroy_inodecache(void)
6101da177e4SLinus Torvalds {
6118c0a8537SKirill A. Shutemov 	/*
6128c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
6138c0a8537SKirill A. Shutemov 	 * destroy cache.
6148c0a8537SKirill A. Shutemov 	 */
6158c0a8537SKirill A. Shutemov 	rcu_barrier();
6161a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(reiserfs_inode_cachep);
6171da177e4SLinus Torvalds }
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds /* we don't mark inodes dirty, we just log them */
620aa385729SChristoph Hellwig static void reiserfs_dirty_inode(struct inode *inode, int flags)
621bd4c625cSLinus Torvalds {
6221da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds 	int err = 0;
625dc8f6d89SFrederic Weisbecker 	int lock_depth;
626dc8f6d89SFrederic Weisbecker 
6271da177e4SLinus Torvalds 	if (inode->i_sb->s_flags & MS_RDONLY) {
62845b03d5eSJeff Mahoney 		reiserfs_warning(inode->i_sb, "clm-6006",
62945b03d5eSJeff Mahoney 				 "writing inode %lu on readonly FS",
6301da177e4SLinus Torvalds 				 inode->i_ino);
6311da177e4SLinus Torvalds 		return;
6321da177e4SLinus Torvalds 	}
633dc8f6d89SFrederic Weisbecker 	lock_depth = reiserfs_write_lock_once(inode->i_sb);
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 	/* this is really only used for atime updates, so they don't have
6361da177e4SLinus Torvalds 	 ** to be included in O_SYNC or fsync
6371da177e4SLinus Torvalds 	 */
6381da177e4SLinus Torvalds 	err = journal_begin(&th, inode->i_sb, 1);
639dc8f6d89SFrederic Weisbecker 	if (err)
640dc8f6d89SFrederic Weisbecker 		goto out;
641dc8f6d89SFrederic Weisbecker 
6421da177e4SLinus Torvalds 	reiserfs_update_sd(&th, inode);
6431da177e4SLinus Torvalds 	journal_end(&th, inode->i_sb, 1);
644dc8f6d89SFrederic Weisbecker 
645dc8f6d89SFrederic Weisbecker out:
646dc8f6d89SFrederic Weisbecker 	reiserfs_write_unlock_once(inode->i_sb, lock_depth);
6471da177e4SLinus Torvalds }
6481da177e4SLinus Torvalds 
649c3aa0776SJan Kara static int reiserfs_show_options(struct seq_file *seq, struct dentry *root)
650c3aa0776SJan Kara {
651c3aa0776SJan Kara 	struct super_block *s = root->d_sb;
652c3aa0776SJan Kara 	struct reiserfs_journal *journal = SB_JOURNAL(s);
653c3aa0776SJan Kara 	long opts = REISERFS_SB(s)->s_mount_opt;
654c3aa0776SJan Kara 
655c3aa0776SJan Kara 	if (opts & (1 << REISERFS_LARGETAIL))
656c3aa0776SJan Kara 		seq_puts(seq, ",tails=on");
657c3aa0776SJan Kara 	else if (!(opts & (1 << REISERFS_SMALLTAIL)))
658c3aa0776SJan Kara 		seq_puts(seq, ",notail");
659c3aa0776SJan Kara 	/* tails=small is default so we don't show it */
660c3aa0776SJan Kara 
661c3aa0776SJan Kara 	if (!(opts & (1 << REISERFS_BARRIER_FLUSH)))
662c3aa0776SJan Kara 		seq_puts(seq, ",barrier=none");
663c3aa0776SJan Kara 	/* barrier=flush is default so we don't show it */
664c3aa0776SJan Kara 
665c3aa0776SJan Kara 	if (opts & (1 << REISERFS_ERROR_CONTINUE))
666c3aa0776SJan Kara 		seq_puts(seq, ",errors=continue");
667c3aa0776SJan Kara 	else if (opts & (1 << REISERFS_ERROR_PANIC))
668c3aa0776SJan Kara 		seq_puts(seq, ",errors=panic");
669c3aa0776SJan Kara 	/* errors=ro is default so we don't show it */
670c3aa0776SJan Kara 
671c3aa0776SJan Kara 	if (opts & (1 << REISERFS_DATA_LOG))
672c3aa0776SJan Kara 		seq_puts(seq, ",data=journal");
673c3aa0776SJan Kara 	else if (opts & (1 << REISERFS_DATA_WRITEBACK))
674c3aa0776SJan Kara 		seq_puts(seq, ",data=writeback");
675c3aa0776SJan Kara 	/* data=ordered is default so we don't show it */
676c3aa0776SJan Kara 
677c3aa0776SJan Kara 	if (opts & (1 << REISERFS_ATTRS))
678c3aa0776SJan Kara 		seq_puts(seq, ",attrs");
679c3aa0776SJan Kara 
680c3aa0776SJan Kara 	if (opts & (1 << REISERFS_XATTRS_USER))
681c3aa0776SJan Kara 		seq_puts(seq, ",user_xattr");
682c3aa0776SJan Kara 
683c3aa0776SJan Kara 	if (opts & (1 << REISERFS_EXPOSE_PRIVROOT))
684c3aa0776SJan Kara 		seq_puts(seq, ",expose_privroot");
685c3aa0776SJan Kara 
686c3aa0776SJan Kara 	if (opts & (1 << REISERFS_POSIXACL))
687c3aa0776SJan Kara 		seq_puts(seq, ",acl");
688c3aa0776SJan Kara 
689c3aa0776SJan Kara 	if (REISERFS_SB(s)->s_jdev)
690c3aa0776SJan Kara 		seq_printf(seq, ",jdev=%s", REISERFS_SB(s)->s_jdev);
691c3aa0776SJan Kara 
692c3aa0776SJan Kara 	if (journal->j_max_commit_age != journal->j_default_max_commit_age)
693c3aa0776SJan Kara 		seq_printf(seq, ",commit=%d", journal->j_max_commit_age);
694c3aa0776SJan Kara 
695c3aa0776SJan Kara #ifdef CONFIG_QUOTA
696c3aa0776SJan Kara 	if (REISERFS_SB(s)->s_qf_names[USRQUOTA])
697c3aa0776SJan Kara 		seq_printf(seq, ",usrjquota=%s", REISERFS_SB(s)->s_qf_names[USRQUOTA]);
698c3aa0776SJan Kara 	else if (opts & (1 << REISERFS_USRQUOTA))
699c3aa0776SJan Kara 		seq_puts(seq, ",usrquota");
700c3aa0776SJan Kara 	if (REISERFS_SB(s)->s_qf_names[GRPQUOTA])
701c3aa0776SJan Kara 		seq_printf(seq, ",grpjquota=%s", REISERFS_SB(s)->s_qf_names[GRPQUOTA]);
702c3aa0776SJan Kara 	else if (opts & (1 << REISERFS_GRPQUOTA))
703c3aa0776SJan Kara 		seq_puts(seq, ",grpquota");
704c3aa0776SJan Kara 	if (REISERFS_SB(s)->s_jquota_fmt) {
705c3aa0776SJan Kara 		if (REISERFS_SB(s)->s_jquota_fmt == QFMT_VFS_OLD)
706c3aa0776SJan Kara 			seq_puts(seq, ",jqfmt=vfsold");
707c3aa0776SJan Kara 		else if (REISERFS_SB(s)->s_jquota_fmt == QFMT_VFS_V0)
708c3aa0776SJan Kara 			seq_puts(seq, ",jqfmt=vfsv0");
709c3aa0776SJan Kara 	}
710c3aa0776SJan Kara #endif
711c3aa0776SJan Kara 
712c3aa0776SJan Kara 	/* Block allocator options */
713c3aa0776SJan Kara 	if (opts & (1 << REISERFS_NO_BORDER))
714c3aa0776SJan Kara 		seq_puts(seq, ",block-allocator=noborder");
715c3aa0776SJan Kara 	if (opts & (1 << REISERFS_NO_UNHASHED_RELOCATION))
716c3aa0776SJan Kara 		seq_puts(seq, ",block-allocator=no_unhashed_relocation");
717c3aa0776SJan Kara 	if (opts & (1 << REISERFS_HASHED_RELOCATION))
718c3aa0776SJan Kara 		seq_puts(seq, ",block-allocator=hashed_relocation");
719c3aa0776SJan Kara 	if (opts & (1 << REISERFS_TEST4))
720c3aa0776SJan Kara 		seq_puts(seq, ",block-allocator=test4");
721c3aa0776SJan Kara 	show_alloc_options(seq, s);
722c3aa0776SJan Kara 	return 0;
723c3aa0776SJan Kara }
724c3aa0776SJan Kara 
7251da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
726bd4c625cSLinus Torvalds static ssize_t reiserfs_quota_write(struct super_block *, int, const char *,
727bd4c625cSLinus Torvalds 				    size_t, loff_t);
728bd4c625cSLinus Torvalds static ssize_t reiserfs_quota_read(struct super_block *, int, char *, size_t,
729bd4c625cSLinus Torvalds 				   loff_t);
7301da177e4SLinus Torvalds #endif
7311da177e4SLinus Torvalds 
732ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations reiserfs_sops = {
7331da177e4SLinus Torvalds 	.alloc_inode = reiserfs_alloc_inode,
7341da177e4SLinus Torvalds 	.destroy_inode = reiserfs_destroy_inode,
7351da177e4SLinus Torvalds 	.write_inode = reiserfs_write_inode,
7361da177e4SLinus Torvalds 	.dirty_inode = reiserfs_dirty_inode,
737845a2cc0SAl Viro 	.evict_inode = reiserfs_evict_inode,
7381da177e4SLinus Torvalds 	.put_super = reiserfs_put_super,
7391da177e4SLinus Torvalds 	.sync_fs = reiserfs_sync_fs,
740c4be0c1dSTakashi Sato 	.freeze_fs = reiserfs_freeze,
741c4be0c1dSTakashi Sato 	.unfreeze_fs = reiserfs_unfreeze,
7421da177e4SLinus Torvalds 	.statfs = reiserfs_statfs,
7431da177e4SLinus Torvalds 	.remount_fs = reiserfs_remount,
744c3aa0776SJan Kara 	.show_options = reiserfs_show_options,
7451da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
7461da177e4SLinus Torvalds 	.quota_read = reiserfs_quota_read,
7471da177e4SLinus Torvalds 	.quota_write = reiserfs_quota_write,
7481da177e4SLinus Torvalds #endif
7491da177e4SLinus Torvalds };
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
7521da177e4SLinus Torvalds #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
7531da177e4SLinus Torvalds 
7541da177e4SLinus Torvalds static int reiserfs_write_dquot(struct dquot *);
7551da177e4SLinus Torvalds static int reiserfs_acquire_dquot(struct dquot *);
7561da177e4SLinus Torvalds static int reiserfs_release_dquot(struct dquot *);
7571da177e4SLinus Torvalds static int reiserfs_mark_dquot_dirty(struct dquot *);
7581da177e4SLinus Torvalds static int reiserfs_write_info(struct super_block *, int);
759f00c9e44SJan Kara static int reiserfs_quota_on(struct super_block *, int, int, struct path *);
7601da177e4SLinus Torvalds 
76161e225dcSAlexey Dobriyan static const struct dquot_operations reiserfs_quota_operations = {
7621da177e4SLinus Torvalds 	.write_dquot = reiserfs_write_dquot,
7631da177e4SLinus Torvalds 	.acquire_dquot = reiserfs_acquire_dquot,
7641da177e4SLinus Torvalds 	.release_dquot = reiserfs_release_dquot,
7651da177e4SLinus Torvalds 	.mark_dirty = reiserfs_mark_dquot_dirty,
7661da177e4SLinus Torvalds 	.write_info = reiserfs_write_info,
7674103003bSJan Kara 	.alloc_dquot	= dquot_alloc,
7684103003bSJan Kara 	.destroy_dquot	= dquot_destroy,
7691da177e4SLinus Torvalds };
7701da177e4SLinus Torvalds 
7710d54b217SAlexey Dobriyan static const struct quotactl_ops reiserfs_qctl_operations = {
7721da177e4SLinus Torvalds 	.quota_on = reiserfs_quota_on,
773287a8095SChristoph Hellwig 	.quota_off = dquot_quota_off,
774287a8095SChristoph Hellwig 	.quota_sync = dquot_quota_sync,
775287a8095SChristoph Hellwig 	.get_info = dquot_get_dqinfo,
776287a8095SChristoph Hellwig 	.set_info = dquot_set_dqinfo,
777287a8095SChristoph Hellwig 	.get_dqblk = dquot_get_dqblk,
778287a8095SChristoph Hellwig 	.set_dqblk = dquot_set_dqblk,
7791da177e4SLinus Torvalds };
7801da177e4SLinus Torvalds #endif
7811da177e4SLinus Torvalds 
78239655164SChristoph Hellwig static const struct export_operations reiserfs_export_ops = {
7831da177e4SLinus Torvalds 	.encode_fh = reiserfs_encode_fh,
784be55caf1SChristoph Hellwig 	.fh_to_dentry = reiserfs_fh_to_dentry,
785be55caf1SChristoph Hellwig 	.fh_to_parent = reiserfs_fh_to_parent,
7861da177e4SLinus Torvalds 	.get_parent = reiserfs_get_parent,
7871da177e4SLinus Torvalds };
7881da177e4SLinus Torvalds 
7891da177e4SLinus Torvalds /* this struct is used in reiserfs_getopt () for containing the value for those
7901da177e4SLinus Torvalds    mount options that have values rather than being toggles. */
7911da177e4SLinus Torvalds typedef struct {
7921da177e4SLinus Torvalds 	char *value;
7931da177e4SLinus Torvalds 	int setmask;		/* bitmask which is to set on mount_options bitmask when this
7941da177e4SLinus Torvalds 				   value is found, 0 is no bits are to be changed. */
7951da177e4SLinus Torvalds 	int clrmask;		/* bitmask which is to clear on mount_options bitmask when  this
7961da177e4SLinus Torvalds 				   value is found, 0 is no bits are to be changed. This is
7971da177e4SLinus Torvalds 				   applied BEFORE setmask */
7981da177e4SLinus Torvalds } arg_desc_t;
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds /* Set this bit in arg_required to allow empty arguments */
8011da177e4SLinus Torvalds #define REISERFS_OPT_ALLOWEMPTY 31
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds /* this struct is used in reiserfs_getopt() for describing the set of reiserfs
8041da177e4SLinus Torvalds    mount options */
8051da177e4SLinus Torvalds typedef struct {
8061da177e4SLinus Torvalds 	char *option_name;
8071da177e4SLinus Torvalds 	int arg_required;	/* 0 if argument is not required, not 0 otherwise */
8081da177e4SLinus Torvalds 	const arg_desc_t *values;	/* list of values accepted by an option */
8091da177e4SLinus Torvalds 	int setmask;		/* bitmask which is to set on mount_options bitmask when this
8101da177e4SLinus Torvalds 				   value is found, 0 is no bits are to be changed. */
8111da177e4SLinus Torvalds 	int clrmask;		/* bitmask which is to clear on mount_options bitmask when  this
8121da177e4SLinus Torvalds 				   value is found, 0 is no bits are to be changed. This is
8131da177e4SLinus Torvalds 				   applied BEFORE setmask */
8141da177e4SLinus Torvalds } opt_desc_t;
8151da177e4SLinus Torvalds 
8161da177e4SLinus Torvalds /* possible values for -o data= */
8171da177e4SLinus Torvalds static const arg_desc_t logging_mode[] = {
818bd4c625cSLinus Torvalds 	{"ordered", 1 << REISERFS_DATA_ORDERED,
819bd4c625cSLinus Torvalds 	 (1 << REISERFS_DATA_LOG | 1 << REISERFS_DATA_WRITEBACK)},
820bd4c625cSLinus Torvalds 	{"journal", 1 << REISERFS_DATA_LOG,
821bd4c625cSLinus Torvalds 	 (1 << REISERFS_DATA_ORDERED | 1 << REISERFS_DATA_WRITEBACK)},
822bd4c625cSLinus Torvalds 	{"writeback", 1 << REISERFS_DATA_WRITEBACK,
823bd4c625cSLinus Torvalds 	 (1 << REISERFS_DATA_ORDERED | 1 << REISERFS_DATA_LOG)},
824cd02b966SVladimir V. Saveliev 	{.value = NULL}
8251da177e4SLinus Torvalds };
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds /* possible values for -o barrier= */
8281da177e4SLinus Torvalds static const arg_desc_t barrier_mode[] = {
8291da177e4SLinus Torvalds 	{"none", 1 << REISERFS_BARRIER_NONE, 1 << REISERFS_BARRIER_FLUSH},
8301da177e4SLinus Torvalds 	{"flush", 1 << REISERFS_BARRIER_FLUSH, 1 << REISERFS_BARRIER_NONE},
831cd02b966SVladimir V. Saveliev 	{.value = NULL}
8321da177e4SLinus Torvalds };
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds /* possible values for "-o block-allocator=" and bits which are to be set in
8351da177e4SLinus Torvalds    s_mount_opt of reiserfs specific part of in-core super block */
8361da177e4SLinus Torvalds static const arg_desc_t balloc[] = {
8371da177e4SLinus Torvalds 	{"noborder", 1 << REISERFS_NO_BORDER, 0},
8381da177e4SLinus Torvalds 	{"border", 0, 1 << REISERFS_NO_BORDER},
8391da177e4SLinus Torvalds 	{"no_unhashed_relocation", 1 << REISERFS_NO_UNHASHED_RELOCATION, 0},
8401da177e4SLinus Torvalds 	{"hashed_relocation", 1 << REISERFS_HASHED_RELOCATION, 0},
8411da177e4SLinus Torvalds 	{"test4", 1 << REISERFS_TEST4, 0},
8421da177e4SLinus Torvalds 	{"notest4", 0, 1 << REISERFS_TEST4},
8431da177e4SLinus Torvalds 	{NULL, 0, 0}
8441da177e4SLinus Torvalds };
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds static const arg_desc_t tails[] = {
8471da177e4SLinus Torvalds 	{"on", 1 << REISERFS_LARGETAIL, 1 << REISERFS_SMALLTAIL},
8481da177e4SLinus Torvalds 	{"off", 0, (1 << REISERFS_LARGETAIL) | (1 << REISERFS_SMALLTAIL)},
8491da177e4SLinus Torvalds 	{"small", 1 << REISERFS_SMALLTAIL, 1 << REISERFS_LARGETAIL},
8501da177e4SLinus Torvalds 	{NULL, 0, 0}
8511da177e4SLinus Torvalds };
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds static const arg_desc_t error_actions[] = {
8541da177e4SLinus Torvalds 	{"panic", 1 << REISERFS_ERROR_PANIC,
8551da177e4SLinus Torvalds 	 (1 << REISERFS_ERROR_RO | 1 << REISERFS_ERROR_CONTINUE)},
8561da177e4SLinus Torvalds 	{"ro-remount", 1 << REISERFS_ERROR_RO,
8571da177e4SLinus Torvalds 	 (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_CONTINUE)},
8581da177e4SLinus Torvalds #ifdef REISERFS_JOURNAL_ERROR_ALLOWS_NO_LOG
8591da177e4SLinus Torvalds 	{"continue", 1 << REISERFS_ERROR_CONTINUE,
8601da177e4SLinus Torvalds 	 (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_RO)},
8611da177e4SLinus Torvalds #endif
8621da177e4SLinus Torvalds 	{NULL, 0, 0},
8631da177e4SLinus Torvalds };
8641da177e4SLinus Torvalds 
8651da177e4SLinus Torvalds /* proceed only one option from a list *cur - string containing of mount options
8661da177e4SLinus Torvalds    opts - array of options which are accepted
8671da177e4SLinus Torvalds    opt_arg - if option is found and requires an argument and if it is specifed
8681da177e4SLinus Torvalds    in the input - pointer to the argument is stored here
8691da177e4SLinus Torvalds    bit_flags - if option requires to set a certain bit - it is set here
8701da177e4SLinus Torvalds    return -1 if unknown option is found, opt->arg_required otherwise */
871bd4c625cSLinus Torvalds static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
872bd4c625cSLinus Torvalds 			   char **opt_arg, unsigned long *bit_flags)
8731da177e4SLinus Torvalds {
8741da177e4SLinus Torvalds 	char *p;
8751da177e4SLinus Torvalds 	/* foo=bar,
8761da177e4SLinus Torvalds 	   ^   ^  ^
8771da177e4SLinus Torvalds 	   |   |  +-- option_end
8781da177e4SLinus Torvalds 	   |   +-- arg_start
8791da177e4SLinus Torvalds 	   +-- option_start
8801da177e4SLinus Torvalds 	 */
8811da177e4SLinus Torvalds 	const opt_desc_t *opt;
8821da177e4SLinus Torvalds 	const arg_desc_t *arg;
8831da177e4SLinus Torvalds 
8841da177e4SLinus Torvalds 	p = *cur;
8851da177e4SLinus Torvalds 
8861da177e4SLinus Torvalds 	/* assume argument cannot contain commas */
8871da177e4SLinus Torvalds 	*cur = strchr(p, ',');
8881da177e4SLinus Torvalds 	if (*cur) {
8891da177e4SLinus Torvalds 		*(*cur) = '\0';
8901da177e4SLinus Torvalds 		(*cur)++;
8911da177e4SLinus Torvalds 	}
8921da177e4SLinus Torvalds 
8931da177e4SLinus Torvalds 	if (!strncmp(p, "alloc=", 6)) {
8941da177e4SLinus Torvalds 		/* Ugly special case, probably we should redo options parser so that
8951da177e4SLinus Torvalds 		   it can understand several arguments for some options, also so that
8961da177e4SLinus Torvalds 		   it can fill several bitfields with option values. */
8971da177e4SLinus Torvalds 		if (reiserfs_parse_alloc_options(s, p + 6)) {
8981da177e4SLinus Torvalds 			return -1;
8991da177e4SLinus Torvalds 		} else {
9001da177e4SLinus Torvalds 			return 0;
9011da177e4SLinus Torvalds 		}
9021da177e4SLinus Torvalds 	}
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds 	/* for every option in the list */
9051da177e4SLinus Torvalds 	for (opt = opts; opt->option_name; opt++) {
9061da177e4SLinus Torvalds 		if (!strncmp(p, opt->option_name, strlen(opt->option_name))) {
9071da177e4SLinus Torvalds 			if (bit_flags) {
908bd4c625cSLinus Torvalds 				if (opt->clrmask ==
909bd4c625cSLinus Torvalds 				    (1 << REISERFS_UNSUPPORTED_OPT))
91045b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6500",
91145b03d5eSJeff Mahoney 							 "%s not supported.\n",
912bd4c625cSLinus Torvalds 							 p);
9131da177e4SLinus Torvalds 				else
9141da177e4SLinus Torvalds 					*bit_flags &= ~opt->clrmask;
915bd4c625cSLinus Torvalds 				if (opt->setmask ==
916bd4c625cSLinus Torvalds 				    (1 << REISERFS_UNSUPPORTED_OPT))
91745b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6501",
91845b03d5eSJeff Mahoney 							 "%s not supported.\n",
919bd4c625cSLinus Torvalds 							 p);
9201da177e4SLinus Torvalds 				else
9211da177e4SLinus Torvalds 					*bit_flags |= opt->setmask;
9221da177e4SLinus Torvalds 			}
9231da177e4SLinus Torvalds 			break;
9241da177e4SLinus Torvalds 		}
9251da177e4SLinus Torvalds 	}
9261da177e4SLinus Torvalds 	if (!opt->option_name) {
92745b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6502",
92845b03d5eSJeff Mahoney 				 "unknown mount option \"%s\"", p);
9291da177e4SLinus Torvalds 		return -1;
9301da177e4SLinus Torvalds 	}
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 	p += strlen(opt->option_name);
9331da177e4SLinus Torvalds 	switch (*p) {
9341da177e4SLinus Torvalds 	case '=':
9351da177e4SLinus Torvalds 		if (!opt->arg_required) {
93645b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6503",
93745b03d5eSJeff Mahoney 					 "the option \"%s\" does not "
93845b03d5eSJeff Mahoney 					 "require an argument\n",
9391da177e4SLinus Torvalds 					 opt->option_name);
9401da177e4SLinus Torvalds 			return -1;
9411da177e4SLinus Torvalds 		}
9421da177e4SLinus Torvalds 		break;
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	case 0:
9451da177e4SLinus Torvalds 		if (opt->arg_required) {
94645b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6504",
94745b03d5eSJeff Mahoney 					 "the option \"%s\" requires an "
94845b03d5eSJeff Mahoney 					 "argument\n", opt->option_name);
9491da177e4SLinus Torvalds 			return -1;
9501da177e4SLinus Torvalds 		}
9511da177e4SLinus Torvalds 		break;
9521da177e4SLinus Torvalds 	default:
95345b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6505",
95445b03d5eSJeff Mahoney 				 "head of option \"%s\" is only correct\n",
955bd4c625cSLinus Torvalds 				 opt->option_name);
9561da177e4SLinus Torvalds 		return -1;
9571da177e4SLinus Torvalds 	}
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds 	/* move to the argument, or to next option if argument is not required */
9601da177e4SLinus Torvalds 	p++;
9611da177e4SLinus Torvalds 
962bd4c625cSLinus Torvalds 	if (opt->arg_required
963bd4c625cSLinus Torvalds 	    && !(opt->arg_required & (1 << REISERFS_OPT_ALLOWEMPTY))
964bd4c625cSLinus Torvalds 	    && !strlen(p)) {
9651da177e4SLinus Torvalds 		/* this catches "option=," if not allowed */
96645b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6506",
96745b03d5eSJeff Mahoney 				 "empty argument for \"%s\"\n",
968bd4c625cSLinus Torvalds 				 opt->option_name);
9691da177e4SLinus Torvalds 		return -1;
9701da177e4SLinus Torvalds 	}
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 	if (!opt->values) {
9731da177e4SLinus Torvalds 		/* *=NULLopt_arg contains pointer to argument */
9741da177e4SLinus Torvalds 		*opt_arg = p;
9751da177e4SLinus Torvalds 		return opt->arg_required & ~(1 << REISERFS_OPT_ALLOWEMPTY);
9761da177e4SLinus Torvalds 	}
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds 	/* values possible for this option are listed in opt->values */
9791da177e4SLinus Torvalds 	for (arg = opt->values; arg->value; arg++) {
9801da177e4SLinus Torvalds 		if (!strcmp(p, arg->value)) {
9811da177e4SLinus Torvalds 			if (bit_flags) {
9821da177e4SLinus Torvalds 				*bit_flags &= ~arg->clrmask;
9831da177e4SLinus Torvalds 				*bit_flags |= arg->setmask;
9841da177e4SLinus Torvalds 			}
9851da177e4SLinus Torvalds 			return opt->arg_required;
9861da177e4SLinus Torvalds 		}
9871da177e4SLinus Torvalds 	}
9881da177e4SLinus Torvalds 
98945b03d5eSJeff Mahoney 	reiserfs_warning(s, "super-6506",
99045b03d5eSJeff Mahoney 			 "bad value \"%s\" for option \"%s\"\n", p,
991bd4c625cSLinus Torvalds 			 opt->option_name);
9921da177e4SLinus Torvalds 	return -1;
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds /* returns 0 if something is wrong in option string, 1 - otherwise */
9961da177e4SLinus Torvalds static int reiserfs_parse_options(struct super_block *s, char *options,	/* string given via mount's -o */
9971da177e4SLinus Torvalds 				  unsigned long *mount_options,
9981da177e4SLinus Torvalds 				  /* after the parsing phase, contains the
9991da177e4SLinus Torvalds 				     collection of bitflags defining what
10001da177e4SLinus Torvalds 				     mount options were selected. */
10011da177e4SLinus Torvalds 				  unsigned long *blocks,	/* strtol-ed from NNN of resize=NNN */
10021da177e4SLinus Torvalds 				  char **jdev_name,
100300b44197SJan Kara 				  unsigned int *commit_max_age,
100400b44197SJan Kara 				  char **qf_names,
100500b44197SJan Kara 				  unsigned int *qfmt)
10061da177e4SLinus Torvalds {
10071da177e4SLinus Torvalds 	int c;
10081da177e4SLinus Torvalds 	char *arg = NULL;
10091da177e4SLinus Torvalds 	char *pos;
10101da177e4SLinus Torvalds 	opt_desc_t opts[] = {
10111da177e4SLinus Torvalds 		/* Compatibility stuff, so that -o notail for old setups still work */
10121da177e4SLinus Torvalds 		{"tails",.arg_required = 't',.values = tails},
1013bd4c625cSLinus Torvalds 		{"notail",.clrmask =
1014bd4c625cSLinus Torvalds 		 (1 << REISERFS_LARGETAIL) | (1 << REISERFS_SMALLTAIL)},
10151da177e4SLinus Torvalds 		{"conv",.setmask = 1 << REISERFS_CONVERT},
10161da177e4SLinus Torvalds 		{"attrs",.setmask = 1 << REISERFS_ATTRS},
10171da177e4SLinus Torvalds 		{"noattrs",.clrmask = 1 << REISERFS_ATTRS},
101873422811SJeff Mahoney 		{"expose_privroot", .setmask = 1 << REISERFS_EXPOSE_PRIVROOT},
10191da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_FS_XATTR
10201da177e4SLinus Torvalds 		{"user_xattr",.setmask = 1 << REISERFS_XATTRS_USER},
10211da177e4SLinus Torvalds 		{"nouser_xattr",.clrmask = 1 << REISERFS_XATTRS_USER},
10221da177e4SLinus Torvalds #else
10231da177e4SLinus Torvalds 		{"user_xattr",.setmask = 1 << REISERFS_UNSUPPORTED_OPT},
10241da177e4SLinus Torvalds 		{"nouser_xattr",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT},
10251da177e4SLinus Torvalds #endif
10261da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_FS_POSIX_ACL
10271da177e4SLinus Torvalds 		{"acl",.setmask = 1 << REISERFS_POSIXACL},
10281da177e4SLinus Torvalds 		{"noacl",.clrmask = 1 << REISERFS_POSIXACL},
10291da177e4SLinus Torvalds #else
10301da177e4SLinus Torvalds 		{"acl",.setmask = 1 << REISERFS_UNSUPPORTED_OPT},
10311da177e4SLinus Torvalds 		{"noacl",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT},
10321da177e4SLinus Torvalds #endif
1033cd02b966SVladimir V. Saveliev 		{.option_name = "nolog"},
10341da177e4SLinus Torvalds 		{"replayonly",.setmask = 1 << REPLAYONLY},
10351da177e4SLinus Torvalds 		{"block-allocator",.arg_required = 'a',.values = balloc},
10361da177e4SLinus Torvalds 		{"data",.arg_required = 'd',.values = logging_mode},
10371da177e4SLinus Torvalds 		{"barrier",.arg_required = 'b',.values = barrier_mode},
10381da177e4SLinus Torvalds 		{"resize",.arg_required = 'r',.values = NULL},
10391da177e4SLinus Torvalds 		{"jdev",.arg_required = 'j',.values = NULL},
10401da177e4SLinus Torvalds 		{"nolargeio",.arg_required = 'w',.values = NULL},
10411da177e4SLinus Torvalds 		{"commit",.arg_required = 'c',.values = NULL},
1042c3aa0776SJan Kara 		{"usrquota",.setmask = 1 << REISERFS_USRQUOTA},
1043c3aa0776SJan Kara 		{"grpquota",.setmask = 1 << REISERFS_GRPQUOTA},
1044c3aa0776SJan Kara 		{"noquota",.clrmask = 1 << REISERFS_USRQUOTA | 1 << REISERFS_GRPQUOTA},
10451da177e4SLinus Torvalds 		{"errors",.arg_required = 'e',.values = error_actions},
1046bd4c625cSLinus Torvalds 		{"usrjquota",.arg_required =
1047bd4c625cSLinus Torvalds 		 'u' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL},
1048bd4c625cSLinus Torvalds 		{"grpjquota",.arg_required =
1049bd4c625cSLinus Torvalds 		 'g' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL},
10501da177e4SLinus Torvalds 		{"jqfmt",.arg_required = 'f',.values = NULL},
1051cd02b966SVladimir V. Saveliev 		{.option_name = NULL}
10521da177e4SLinus Torvalds 	};
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 	*blocks = 0;
10551da177e4SLinus Torvalds 	if (!options || !*options)
10561da177e4SLinus Torvalds 		/* use default configuration: create tails, journaling on, no
10571da177e4SLinus Torvalds 		   conversion to newest format */
10581da177e4SLinus Torvalds 		return 1;
10591da177e4SLinus Torvalds 
10601da177e4SLinus Torvalds 	for (pos = options; pos;) {
10611da177e4SLinus Torvalds 		c = reiserfs_getopt(s, &pos, opts, &arg, mount_options);
10621da177e4SLinus Torvalds 		if (c == -1)
10631da177e4SLinus Torvalds 			/* wrong option is given */
10641da177e4SLinus Torvalds 			return 0;
10651da177e4SLinus Torvalds 
10661da177e4SLinus Torvalds 		if (c == 'r') {
10671da177e4SLinus Torvalds 			char *p;
10681da177e4SLinus Torvalds 
10691da177e4SLinus Torvalds 			p = NULL;
10709a3bb301SPaolo 'Blaisorblade' Giarrusso 			/* "resize=NNN" or "resize=auto" */
10719a3bb301SPaolo 'Blaisorblade' Giarrusso 
10729a3bb301SPaolo 'Blaisorblade' Giarrusso 			if (!strcmp(arg, "auto")) {
10739a3bb301SPaolo 'Blaisorblade' Giarrusso 				/* From JFS code, to auto-get the size. */
1074bd4c625cSLinus Torvalds 				*blocks =
1075bd4c625cSLinus Torvalds 				    s->s_bdev->bd_inode->i_size >> s->
1076bd4c625cSLinus Torvalds 				    s_blocksize_bits;
10779a3bb301SPaolo 'Blaisorblade' Giarrusso 			} else {
10781da177e4SLinus Torvalds 				*blocks = simple_strtoul(arg, &p, 0);
10791da177e4SLinus Torvalds 				if (*p != '\0') {
10801da177e4SLinus Torvalds 					/* NNN does not look like a number */
108145b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6507",
108245b03d5eSJeff Mahoney 							 "bad value %s for "
108345b03d5eSJeff Mahoney 							 "-oresize\n", arg);
10841da177e4SLinus Torvalds 					return 0;
10851da177e4SLinus Torvalds 				}
10861da177e4SLinus Torvalds 			}
10879a3bb301SPaolo 'Blaisorblade' Giarrusso 		}
10881da177e4SLinus Torvalds 
10891da177e4SLinus Torvalds 		if (c == 'c') {
10901da177e4SLinus Torvalds 			char *p = NULL;
10911da177e4SLinus Torvalds 			unsigned long val = simple_strtoul(arg, &p, 0);
10921da177e4SLinus Torvalds 			/* commit=NNN (time in seconds) */
10931da177e4SLinus Torvalds 			if (*p != '\0' || val >= (unsigned int)-1) {
109445b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-6508",
109545b03d5eSJeff Mahoney 						 "bad value %s for -ocommit\n",
1096bd4c625cSLinus Torvalds 						 arg);
10979a3bb301SPaolo 'Blaisorblade' Giarrusso 				return 0;
10981da177e4SLinus Torvalds 			}
10991da177e4SLinus Torvalds 			*commit_max_age = (unsigned int)val;
11001da177e4SLinus Torvalds 		}
11011da177e4SLinus Torvalds 
11021da177e4SLinus Torvalds 		if (c == 'w') {
110345b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6509", "nolargeio option "
110445b03d5eSJeff Mahoney 					 "is no longer supported");
11051da177e4SLinus Torvalds 			return 0;
11061da177e4SLinus Torvalds 		}
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds 		if (c == 'j') {
11091da177e4SLinus Torvalds 			if (arg && *arg && jdev_name) {
11101da177e4SLinus Torvalds 				if (*jdev_name) {	//Hm, already assigned?
111145b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6510",
111245b03d5eSJeff Mahoney 							 "journal device was "
111345b03d5eSJeff Mahoney 							 "already specified to "
111445b03d5eSJeff Mahoney 							 "be %s", *jdev_name);
11151da177e4SLinus Torvalds 					return 0;
11161da177e4SLinus Torvalds 				}
11171da177e4SLinus Torvalds 				*jdev_name = arg;
11181da177e4SLinus Torvalds 			}
11191da177e4SLinus Torvalds 		}
11201da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
11211da177e4SLinus Torvalds 		if (c == 'u' || c == 'g') {
11221da177e4SLinus Torvalds 			int qtype = c == 'u' ? USRQUOTA : GRPQUOTA;
11231da177e4SLinus Torvalds 
11246929f891SJan Kara 			if (sb_any_quota_loaded(s) &&
112500b44197SJan Kara 			    (!*arg != !REISERFS_SB(s)->s_qf_names[qtype])) {
112645b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-6511",
112745b03d5eSJeff Mahoney 						 "cannot change journaled "
112845b03d5eSJeff Mahoney 						 "quota options when quota "
112945b03d5eSJeff Mahoney 						 "turned on.");
11301da177e4SLinus Torvalds 				return 0;
11311da177e4SLinus Torvalds 			}
11321da177e4SLinus Torvalds 			if (*arg) {	/* Some filename specified? */
1133bd4c625cSLinus Torvalds 				if (REISERFS_SB(s)->s_qf_names[qtype]
1134bd4c625cSLinus Torvalds 				    && strcmp(REISERFS_SB(s)->s_qf_names[qtype],
1135bd4c625cSLinus Torvalds 					      arg)) {
113645b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6512",
113745b03d5eSJeff Mahoney 							 "%s quota file "
113845b03d5eSJeff Mahoney 							 "already specified.",
1139bd4c625cSLinus Torvalds 							 QTYPE2NAME(qtype));
11401da177e4SLinus Torvalds 					return 0;
11411da177e4SLinus Torvalds 				}
11421da177e4SLinus Torvalds 				if (strchr(arg, '/')) {
114345b03d5eSJeff Mahoney 					reiserfs_warning(s, "super-6513",
114445b03d5eSJeff Mahoney 							 "quotafile must be "
114545b03d5eSJeff Mahoney 							 "on filesystem root.");
11461da177e4SLinus Torvalds 					return 0;
11471da177e4SLinus Torvalds 				}
114800b44197SJan Kara 				qf_names[qtype] =
1149bd4c625cSLinus Torvalds 				    kmalloc(strlen(arg) + 1, GFP_KERNEL);
115000b44197SJan Kara 				if (!qf_names[qtype]) {
115145b03d5eSJeff Mahoney 					reiserfs_warning(s, "reiserfs-2502",
115245b03d5eSJeff Mahoney 							 "not enough memory "
115345b03d5eSJeff Mahoney 							 "for storing "
115445b03d5eSJeff Mahoney 							 "quotafile name.");
11551da177e4SLinus Torvalds 					return 0;
11561da177e4SLinus Torvalds 				}
115700b44197SJan Kara 				strcpy(qf_names[qtype], arg);
1158c3aa0776SJan Kara 				if (qtype == USRQUOTA)
1159c3aa0776SJan Kara 					*mount_options |= 1 << REISERFS_USRQUOTA;
1160c3aa0776SJan Kara 				else
1161c3aa0776SJan Kara 					*mount_options |= 1 << REISERFS_GRPQUOTA;
1162bd4c625cSLinus Torvalds 			} else {
116300b44197SJan Kara 				if (qf_names[qtype] !=
116400b44197SJan Kara 				    REISERFS_SB(s)->s_qf_names[qtype])
116500b44197SJan Kara 					kfree(qf_names[qtype]);
116600b44197SJan Kara 				qf_names[qtype] = NULL;
1167c3aa0776SJan Kara 				if (qtype == USRQUOTA)
1168c3aa0776SJan Kara 					*mount_options &= ~(1 << REISERFS_USRQUOTA);
1169c3aa0776SJan Kara 				else
1170c3aa0776SJan Kara 					*mount_options &= ~(1 << REISERFS_GRPQUOTA);
11711da177e4SLinus Torvalds 			}
11721da177e4SLinus Torvalds 		}
11731da177e4SLinus Torvalds 		if (c == 'f') {
11741da177e4SLinus Torvalds 			if (!strcmp(arg, "vfsold"))
117500b44197SJan Kara 				*qfmt = QFMT_VFS_OLD;
11761da177e4SLinus Torvalds 			else if (!strcmp(arg, "vfsv0"))
117700b44197SJan Kara 				*qfmt = QFMT_VFS_V0;
11781da177e4SLinus Torvalds 			else {
117945b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-6514",
118045b03d5eSJeff Mahoney 						 "unknown quota format "
118145b03d5eSJeff Mahoney 						 "specified.");
11821da177e4SLinus Torvalds 				return 0;
11831da177e4SLinus Torvalds 			}
11846929f891SJan Kara 			if (sb_any_quota_loaded(s) &&
118500b44197SJan Kara 			    *qfmt != REISERFS_SB(s)->s_jquota_fmt) {
118645b03d5eSJeff Mahoney 				reiserfs_warning(s, "super-6515",
118745b03d5eSJeff Mahoney 						 "cannot change journaled "
118845b03d5eSJeff Mahoney 						 "quota options when quota "
118945b03d5eSJeff Mahoney 						 "turned on.");
119000b44197SJan Kara 				return 0;
119100b44197SJan Kara 			}
11921da177e4SLinus Torvalds 		}
11931da177e4SLinus Torvalds #else
11941da177e4SLinus Torvalds 		if (c == 'u' || c == 'g' || c == 'f') {
119545b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2503", "journaled "
119645b03d5eSJeff Mahoney 					 "quota options not supported.");
11971da177e4SLinus Torvalds 			return 0;
11981da177e4SLinus Torvalds 		}
11991da177e4SLinus Torvalds #endif
12001da177e4SLinus Torvalds 	}
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
120300b44197SJan Kara 	if (!REISERFS_SB(s)->s_jquota_fmt && !*qfmt
120400b44197SJan Kara 	    && (qf_names[USRQUOTA] || qf_names[GRPQUOTA])) {
120545b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6515",
120645b03d5eSJeff Mahoney 				 "journaled quota format not specified.");
12071da177e4SLinus Torvalds 		return 0;
12081da177e4SLinus Torvalds 	}
1209c3aa0776SJan Kara 	if ((!(*mount_options & (1 << REISERFS_USRQUOTA)) &&
1210c3aa0776SJan Kara 	       sb_has_quota_loaded(s, USRQUOTA)) ||
1211c3aa0776SJan Kara 	    (!(*mount_options & (1 << REISERFS_GRPQUOTA)) &&
1212c3aa0776SJan Kara 	       sb_has_quota_loaded(s, GRPQUOTA))) {
121345b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6516", "quota options must "
121445b03d5eSJeff Mahoney 				 "be present when quota is turned on.");
1215556a2a45SJan Kara 		return 0;
1216556a2a45SJan Kara 	}
12171da177e4SLinus Torvalds #endif
1218556a2a45SJan Kara 
12191da177e4SLinus Torvalds 	return 1;
12201da177e4SLinus Torvalds }
12211da177e4SLinus Torvalds 
1222bd4c625cSLinus Torvalds static void switch_data_mode(struct super_block *s, unsigned long mode)
1223bd4c625cSLinus Torvalds {
12241da177e4SLinus Torvalds 	REISERFS_SB(s)->s_mount_opt &= ~((1 << REISERFS_DATA_LOG) |
12251da177e4SLinus Torvalds 					 (1 << REISERFS_DATA_ORDERED) |
12261da177e4SLinus Torvalds 					 (1 << REISERFS_DATA_WRITEBACK));
12271da177e4SLinus Torvalds 	REISERFS_SB(s)->s_mount_opt |= (1 << mode);
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds 
12301da177e4SLinus Torvalds static void handle_data_mode(struct super_block *s, unsigned long mount_options)
12311da177e4SLinus Torvalds {
12321da177e4SLinus Torvalds 	if (mount_options & (1 << REISERFS_DATA_LOG)) {
12331da177e4SLinus Torvalds 		if (!reiserfs_data_log(s)) {
12341da177e4SLinus Torvalds 			switch_data_mode(s, REISERFS_DATA_LOG);
12351da177e4SLinus Torvalds 			reiserfs_info(s, "switching to journaled data mode\n");
12361da177e4SLinus Torvalds 		}
12371da177e4SLinus Torvalds 	} else if (mount_options & (1 << REISERFS_DATA_ORDERED)) {
12381da177e4SLinus Torvalds 		if (!reiserfs_data_ordered(s)) {
12391da177e4SLinus Torvalds 			switch_data_mode(s, REISERFS_DATA_ORDERED);
12401da177e4SLinus Torvalds 			reiserfs_info(s, "switching to ordered data mode\n");
12411da177e4SLinus Torvalds 		}
12421da177e4SLinus Torvalds 	} else if (mount_options & (1 << REISERFS_DATA_WRITEBACK)) {
12431da177e4SLinus Torvalds 		if (!reiserfs_data_writeback(s)) {
12441da177e4SLinus Torvalds 			switch_data_mode(s, REISERFS_DATA_WRITEBACK);
12451da177e4SLinus Torvalds 			reiserfs_info(s, "switching to writeback data mode\n");
12461da177e4SLinus Torvalds 		}
12471da177e4SLinus Torvalds 	}
12481da177e4SLinus Torvalds }
12491da177e4SLinus Torvalds 
1250bd4c625cSLinus Torvalds static void handle_barrier_mode(struct super_block *s, unsigned long bits)
1251bd4c625cSLinus Torvalds {
12521da177e4SLinus Torvalds 	int flush = (1 << REISERFS_BARRIER_FLUSH);
12531da177e4SLinus Torvalds 	int none = (1 << REISERFS_BARRIER_NONE);
12541da177e4SLinus Torvalds 	int all_barrier = flush | none;
12551da177e4SLinus Torvalds 
12561da177e4SLinus Torvalds 	if (bits & all_barrier) {
12571da177e4SLinus Torvalds 		REISERFS_SB(s)->s_mount_opt &= ~all_barrier;
12581da177e4SLinus Torvalds 		if (bits & flush) {
12591da177e4SLinus Torvalds 			REISERFS_SB(s)->s_mount_opt |= flush;
12601da177e4SLinus Torvalds 			printk("reiserfs: enabling write barrier flush mode\n");
12611da177e4SLinus Torvalds 		} else if (bits & none) {
12621da177e4SLinus Torvalds 			REISERFS_SB(s)->s_mount_opt |= none;
12631da177e4SLinus Torvalds 			printk("reiserfs: write barriers turned off\n");
12641da177e4SLinus Torvalds 		}
12651da177e4SLinus Torvalds 	}
12661da177e4SLinus Torvalds }
12671da177e4SLinus Torvalds 
12681da177e4SLinus Torvalds static void handle_attrs(struct super_block *s)
12691da177e4SLinus Torvalds {
1270c60e81eeSAndrew Morton 	struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
12711da177e4SLinus Torvalds 
12721da177e4SLinus Torvalds 	if (reiserfs_attrs(s)) {
12731da177e4SLinus Torvalds 		if (old_format_only(s)) {
127445b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6517", "cannot support "
127545b03d5eSJeff Mahoney 					 "attributes on 3.5.x disk format");
12761da177e4SLinus Torvalds 			REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
12771da177e4SLinus Torvalds 			return;
12781da177e4SLinus Torvalds 		}
12791da177e4SLinus Torvalds 		if (!(le32_to_cpu(rs->s_flags) & reiserfs_attrs_cleared)) {
128045b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-6518", "cannot support "
128145b03d5eSJeff Mahoney 					 "attributes until flag is set in "
128245b03d5eSJeff Mahoney 					 "super-block");
12831da177e4SLinus Torvalds 			REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
12841da177e4SLinus Torvalds 		}
12851da177e4SLinus Torvalds 	}
12861da177e4SLinus Torvalds }
12871da177e4SLinus Torvalds 
128800b44197SJan Kara #ifdef CONFIG_QUOTA
128900b44197SJan Kara static void handle_quota_files(struct super_block *s, char **qf_names,
129000b44197SJan Kara 			       unsigned int *qfmt)
129100b44197SJan Kara {
129200b44197SJan Kara 	int i;
129300b44197SJan Kara 
129400b44197SJan Kara 	for (i = 0; i < MAXQUOTAS; i++) {
129500b44197SJan Kara 		if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i])
129600b44197SJan Kara 			kfree(REISERFS_SB(s)->s_qf_names[i]);
129700b44197SJan Kara 		REISERFS_SB(s)->s_qf_names[i] = qf_names[i];
129800b44197SJan Kara 	}
1299a06d789bSJan Kara 	if (*qfmt)
130000b44197SJan Kara 		REISERFS_SB(s)->s_jquota_fmt = *qfmt;
130100b44197SJan Kara }
130200b44197SJan Kara #endif
130300b44197SJan Kara 
13041da177e4SLinus Torvalds static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
13051da177e4SLinus Torvalds {
13061da177e4SLinus Torvalds 	struct reiserfs_super_block *rs;
13071da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
13081da177e4SLinus Torvalds 	unsigned long blocks;
13091da177e4SLinus Torvalds 	unsigned long mount_options = REISERFS_SB(s)->s_mount_opt;
13101da177e4SLinus Torvalds 	unsigned long safe_mask = 0;
13111da177e4SLinus Torvalds 	unsigned int commit_max_age = (unsigned int)-1;
13121da177e4SLinus Torvalds 	struct reiserfs_journal *journal = SB_JOURNAL(s);
1313cdf6ccc8SMiklos Szeredi 	char *new_opts = kstrdup(arg, GFP_KERNEL);
13141da177e4SLinus Torvalds 	int err;
131500b44197SJan Kara 	char *qf_names[MAXQUOTAS];
131600b44197SJan Kara 	unsigned int qfmt = 0;
13171da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
13181da177e4SLinus Torvalds 	int i;
13198ebc4232SFrederic Weisbecker #endif
132000b44197SJan Kara 
13218ebc4232SFrederic Weisbecker 	reiserfs_write_lock(s);
13228ebc4232SFrederic Weisbecker 
13238ebc4232SFrederic Weisbecker #ifdef CONFIG_QUOTA
132400b44197SJan Kara 	memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names));
13251da177e4SLinus Torvalds #endif
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds 	rs = SB_DISK_SUPER_BLOCK(s);
13281da177e4SLinus Torvalds 
1329bd4c625cSLinus Torvalds 	if (!reiserfs_parse_options
133000b44197SJan Kara 	    (s, arg, &mount_options, &blocks, NULL, &commit_max_age,
133100b44197SJan Kara 	    qf_names, &qfmt)) {
13321da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
133300b44197SJan Kara 		for (i = 0; i < MAXQUOTAS; i++)
133400b44197SJan Kara 			if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i])
133500b44197SJan Kara 				kfree(qf_names[i]);
13361da177e4SLinus Torvalds #endif
1337cdf6ccc8SMiklos Szeredi 		err = -EINVAL;
13383bb3e1fcSJan Kara 		goto out_unlock;
13391da177e4SLinus Torvalds 	}
134000b44197SJan Kara #ifdef CONFIG_QUOTA
134100b44197SJan Kara 	handle_quota_files(s, qf_names, &qfmt);
134200b44197SJan Kara #endif
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds 	handle_attrs(s);
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	/* Add options that are safe here */
13471da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_SMALLTAIL;
13481da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_LARGETAIL;
13491da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_NO_BORDER;
13501da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_NO_UNHASHED_RELOCATION;
13511da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_HASHED_RELOCATION;
13521da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_TEST4;
13531da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_ATTRS;
13541da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_XATTRS_USER;
13551da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_POSIXACL;
13561da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
13571da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_BARRIER_NONE;
13581da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_ERROR_RO;
13591da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_ERROR_CONTINUE;
13601da177e4SLinus Torvalds 	safe_mask |= 1 << REISERFS_ERROR_PANIC;
1361c3aa0776SJan Kara 	safe_mask |= 1 << REISERFS_USRQUOTA;
1362c3aa0776SJan Kara 	safe_mask |= 1 << REISERFS_GRPQUOTA;
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 	/* Update the bitmask, taking care to keep
13651da177e4SLinus Torvalds 	 * the bits we're not allowed to change here */
1366bd4c625cSLinus Torvalds 	REISERFS_SB(s)->s_mount_opt =
1367bd4c625cSLinus Torvalds 	    (REISERFS_SB(s)->
1368bd4c625cSLinus Torvalds 	     s_mount_opt & ~safe_mask) | (mount_options & safe_mask);
13691da177e4SLinus Torvalds 
13701da177e4SLinus Torvalds 	if (commit_max_age != 0 && commit_max_age != (unsigned int)-1) {
13711da177e4SLinus Torvalds 		journal->j_max_commit_age = commit_max_age;
13721da177e4SLinus Torvalds 		journal->j_max_trans_age = commit_max_age;
1373bd4c625cSLinus Torvalds 	} else if (commit_max_age == 0) {
13741da177e4SLinus Torvalds 		/* 0 means restore defaults. */
13751da177e4SLinus Torvalds 		journal->j_max_commit_age = journal->j_default_max_commit_age;
13761da177e4SLinus Torvalds 		journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE;
13771da177e4SLinus Torvalds 	}
13781da177e4SLinus Torvalds 
13791da177e4SLinus Torvalds 	if (blocks) {
1380cdf6ccc8SMiklos Szeredi 		err = reiserfs_resize(s, blocks);
1381cdf6ccc8SMiklos Szeredi 		if (err != 0)
13823bb3e1fcSJan Kara 			goto out_unlock;
13831da177e4SLinus Torvalds 	}
13841da177e4SLinus Torvalds 
13851da177e4SLinus Torvalds 	if (*mount_flags & MS_RDONLY) {
13861da177e4SLinus Torvalds 		reiserfs_xattr_init(s, *mount_flags);
13871da177e4SLinus Torvalds 		/* remount read-only */
13881da177e4SLinus Torvalds 		if (s->s_flags & MS_RDONLY)
13891da177e4SLinus Torvalds 			/* it is read-only already */
1390cdf6ccc8SMiklos Szeredi 			goto out_ok;
1391c79d967dSChristoph Hellwig 
13923bb3e1fcSJan Kara 		/*
13933bb3e1fcSJan Kara 		 * Drop write lock. Quota will retake it when needed and lock
13943bb3e1fcSJan Kara 		 * ordering requires calling dquot_suspend() without it.
13953bb3e1fcSJan Kara 		 */
13963bb3e1fcSJan Kara 		reiserfs_write_unlock(s);
13970f0dd62fSChristoph Hellwig 		err = dquot_suspend(s, -1);
13980f0dd62fSChristoph Hellwig 		if (err < 0)
1399c79d967dSChristoph Hellwig 			goto out_err;
14003bb3e1fcSJan Kara 		reiserfs_write_lock(s);
1401c79d967dSChristoph Hellwig 
14021da177e4SLinus Torvalds 		/* try to remount file system with read-only permissions */
1403bd4c625cSLinus Torvalds 		if (sb_umount_state(rs) == REISERFS_VALID_FS
1404bd4c625cSLinus Torvalds 		    || REISERFS_SB(s)->s_mount_state != REISERFS_VALID_FS) {
1405cdf6ccc8SMiklos Szeredi 			goto out_ok;
14061da177e4SLinus Torvalds 		}
14071da177e4SLinus Torvalds 
14081da177e4SLinus Torvalds 		err = journal_begin(&th, s, 10);
14091da177e4SLinus Torvalds 		if (err)
14103bb3e1fcSJan Kara 			goto out_unlock;
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds 		/* Mounting a rw partition read-only. */
14131da177e4SLinus Torvalds 		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
14141da177e4SLinus Torvalds 		set_sb_umount_state(rs, REISERFS_SB(s)->s_mount_state);
14151da177e4SLinus Torvalds 		journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
14161da177e4SLinus Torvalds 	} else {
14171da177e4SLinus Torvalds 		/* remount read-write */
14181da177e4SLinus Torvalds 		if (!(s->s_flags & MS_RDONLY)) {
14191da177e4SLinus Torvalds 			reiserfs_xattr_init(s, *mount_flags);
1420cdf6ccc8SMiklos Szeredi 			goto out_ok;	/* We are read-write already */
14211da177e4SLinus Torvalds 		}
14221da177e4SLinus Torvalds 
1423cdf6ccc8SMiklos Szeredi 		if (reiserfs_is_journal_aborted(journal)) {
1424cdf6ccc8SMiklos Szeredi 			err = journal->j_errno;
14253bb3e1fcSJan Kara 			goto out_unlock;
1426cdf6ccc8SMiklos Szeredi 		}
14271da177e4SLinus Torvalds 
14281da177e4SLinus Torvalds 		handle_data_mode(s, mount_options);
14291da177e4SLinus Torvalds 		handle_barrier_mode(s, mount_options);
14301da177e4SLinus Torvalds 		REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
14311da177e4SLinus Torvalds 		s->s_flags &= ~MS_RDONLY;	/* now it is safe to call journal_begin */
14321da177e4SLinus Torvalds 		err = journal_begin(&th, s, 10);
14331da177e4SLinus Torvalds 		if (err)
14343bb3e1fcSJan Kara 			goto out_unlock;
14351da177e4SLinus Torvalds 
14361da177e4SLinus Torvalds 		/* Mount a partition which is read-only, read-write */
14371da177e4SLinus Torvalds 		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
14381da177e4SLinus Torvalds 		REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
14391da177e4SLinus Torvalds 		s->s_flags &= ~MS_RDONLY;
14401da177e4SLinus Torvalds 		set_sb_umount_state(rs, REISERFS_ERROR_FS);
1441702d21c6SJeff Mahoney 		if (!old_format_only(s))
1442702d21c6SJeff Mahoney 			set_sb_mnt_count(rs, sb_mnt_count(rs) + 1);
14431da177e4SLinus Torvalds 		/* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */
14441da177e4SLinus Torvalds 		journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
14451da177e4SLinus Torvalds 		REISERFS_SB(s)->s_mount_state = REISERFS_VALID_FS;
14461da177e4SLinus Torvalds 	}
14471da177e4SLinus Torvalds 	/* this will force a full flush of all journal lists */
14481da177e4SLinus Torvalds 	SB_JOURNAL(s)->j_must_wait = 1;
14491da177e4SLinus Torvalds 	err = journal_end(&th, s, 10);
14501da177e4SLinus Torvalds 	if (err)
14513bb3e1fcSJan Kara 		goto out_unlock;
14521da177e4SLinus Torvalds 
14531da177e4SLinus Torvalds 	if (!(*mount_flags & MS_RDONLY)) {
14543bb3e1fcSJan Kara 		/*
14553bb3e1fcSJan Kara 		 * Drop write lock. Quota will retake it when needed and lock
14563bb3e1fcSJan Kara 		 * ordering requires calling dquot_resume() without it.
14573bb3e1fcSJan Kara 		 */
14583bb3e1fcSJan Kara 		reiserfs_write_unlock(s);
14590f0dd62fSChristoph Hellwig 		dquot_resume(s, -1);
14603bb3e1fcSJan Kara 		reiserfs_write_lock(s);
14611da177e4SLinus Torvalds 		finish_unfinished(s);
14621da177e4SLinus Torvalds 		reiserfs_xattr_init(s, *mount_flags);
14631da177e4SLinus Torvalds 	}
14641da177e4SLinus Torvalds 
1465cdf6ccc8SMiklos Szeredi out_ok:
14662a32cebdSAl Viro 	replace_mount_options(s, new_opts);
14678ebc4232SFrederic Weisbecker 	reiserfs_write_unlock(s);
14681da177e4SLinus Torvalds 	return 0;
1469cdf6ccc8SMiklos Szeredi 
14703bb3e1fcSJan Kara out_unlock:
14713bb3e1fcSJan Kara 	reiserfs_write_unlock(s);
1472cdf6ccc8SMiklos Szeredi out_err:
1473cdf6ccc8SMiklos Szeredi 	kfree(new_opts);
1474cdf6ccc8SMiklos Szeredi 	return err;
14751da177e4SLinus Torvalds }
14761da177e4SLinus Torvalds 
14771da177e4SLinus Torvalds static int read_super_block(struct super_block *s, int offset)
14781da177e4SLinus Torvalds {
14791da177e4SLinus Torvalds 	struct buffer_head *bh;
14801da177e4SLinus Torvalds 	struct reiserfs_super_block *rs;
14811da177e4SLinus Torvalds 	int fs_blocksize;
14821da177e4SLinus Torvalds 
14831da177e4SLinus Torvalds 	bh = sb_bread(s, offset / s->s_blocksize);
14841da177e4SLinus Torvalds 	if (!bh) {
148545b03d5eSJeff Mahoney 		reiserfs_warning(s, "sh-2006",
14861da177e4SLinus Torvalds 				 "bread failed (dev %s, block %lu, size %lu)",
1487bd4c625cSLinus Torvalds 				 reiserfs_bdevname(s), offset / s->s_blocksize,
1488bd4c625cSLinus Torvalds 				 s->s_blocksize);
14891da177e4SLinus Torvalds 		return 1;
14901da177e4SLinus Torvalds 	}
14911da177e4SLinus Torvalds 
14921da177e4SLinus Torvalds 	rs = (struct reiserfs_super_block *)bh->b_data;
14931da177e4SLinus Torvalds 	if (!is_any_reiserfs_magic_string(rs)) {
14941da177e4SLinus Torvalds 		brelse(bh);
14951da177e4SLinus Torvalds 		return 1;
14961da177e4SLinus Torvalds 	}
14971da177e4SLinus Torvalds 	//
14981da177e4SLinus Torvalds 	// ok, reiserfs signature (old or new) found in at the given offset
14991da177e4SLinus Torvalds 	//
15001da177e4SLinus Torvalds 	fs_blocksize = sb_blocksize(rs);
15011da177e4SLinus Torvalds 	brelse(bh);
15021da177e4SLinus Torvalds 	sb_set_blocksize(s, fs_blocksize);
15031da177e4SLinus Torvalds 
15041da177e4SLinus Torvalds 	bh = sb_bread(s, offset / s->s_blocksize);
15051da177e4SLinus Torvalds 	if (!bh) {
150645b03d5eSJeff Mahoney 		reiserfs_warning(s, "sh-2007",
150745b03d5eSJeff Mahoney 				 "bread failed (dev %s, block %lu, size %lu)",
1508bd4c625cSLinus Torvalds 				 reiserfs_bdevname(s), offset / s->s_blocksize,
1509bd4c625cSLinus Torvalds 				 s->s_blocksize);
15101da177e4SLinus Torvalds 		return 1;
15111da177e4SLinus Torvalds 	}
15121da177e4SLinus Torvalds 
15131da177e4SLinus Torvalds 	rs = (struct reiserfs_super_block *)bh->b_data;
15141da177e4SLinus Torvalds 	if (sb_blocksize(rs) != s->s_blocksize) {
151545b03d5eSJeff Mahoney 		reiserfs_warning(s, "sh-2011", "can't find a reiserfs "
151645b03d5eSJeff Mahoney 				 "filesystem on (dev %s, block %Lu, size %lu)",
1517bd4c625cSLinus Torvalds 				 reiserfs_bdevname(s),
1518bd4c625cSLinus Torvalds 				 (unsigned long long)bh->b_blocknr,
1519bd4c625cSLinus Torvalds 				 s->s_blocksize);
15201da177e4SLinus Torvalds 		brelse(bh);
15211da177e4SLinus Torvalds 		return 1;
15221da177e4SLinus Torvalds 	}
15231da177e4SLinus Torvalds 
15243e8962beSAl Viro 	if (rs->s_v1.s_root_block == cpu_to_le32(-1)) {
15251da177e4SLinus Torvalds 		brelse(bh);
152645b03d5eSJeff Mahoney 		reiserfs_warning(s, "super-6519", "Unfinished reiserfsck "
152745b03d5eSJeff Mahoney 				 "--rebuild-tree run detected. Please run\n"
152845b03d5eSJeff Mahoney 				 "reiserfsck --rebuild-tree and wait for a "
152945b03d5eSJeff Mahoney 				 "completion. If that fails\n"
15301da177e4SLinus Torvalds 				 "get newer reiserfsprogs package");
15311da177e4SLinus Torvalds 		return 1;
15321da177e4SLinus Torvalds 	}
15331da177e4SLinus Torvalds 
15341da177e4SLinus Torvalds 	SB_BUFFER_WITH_SB(s) = bh;
15351da177e4SLinus Torvalds 	SB_DISK_SUPER_BLOCK(s) = rs;
15361da177e4SLinus Torvalds 
15371da177e4SLinus Torvalds 	if (is_reiserfs_jr(rs)) {
15381da177e4SLinus Torvalds 		/* magic is of non-standard journal filesystem, look at s_version to
15391da177e4SLinus Torvalds 		   find which format is in use */
15401da177e4SLinus Torvalds 		if (sb_version(rs) == REISERFS_VERSION_2)
15411d889d99SJeff Mahoney 			reiserfs_info(s, "found reiserfs format \"3.6\""
15421d889d99SJeff Mahoney 				      " with non-standard journal\n");
15431da177e4SLinus Torvalds 		else if (sb_version(rs) == REISERFS_VERSION_1)
15441d889d99SJeff Mahoney 			reiserfs_info(s, "found reiserfs format \"3.5\""
15451d889d99SJeff Mahoney 				      " with non-standard journal\n");
15461da177e4SLinus Torvalds 		else {
154745b03d5eSJeff Mahoney 			reiserfs_warning(s, "sh-2012", "found unknown "
154845b03d5eSJeff Mahoney 					 "format \"%u\" of reiserfs with "
154945b03d5eSJeff Mahoney 					 "non-standard magic", sb_version(rs));
15501da177e4SLinus Torvalds 			return 1;
15511da177e4SLinus Torvalds 		}
1552bd4c625cSLinus Torvalds 	} else
15531da177e4SLinus Torvalds 		/* s_version of standard format may contain incorrect information,
15541da177e4SLinus Torvalds 		   so we just look at the magic string */
1555bd4c625cSLinus Torvalds 		reiserfs_info(s,
1556bd4c625cSLinus Torvalds 			      "found reiserfs format \"%s\" with standard journal\n",
15571da177e4SLinus Torvalds 			      is_reiserfs_3_5(rs) ? "3.5" : "3.6");
15581da177e4SLinus Torvalds 
15591da177e4SLinus Torvalds 	s->s_op = &reiserfs_sops;
15601da177e4SLinus Torvalds 	s->s_export_op = &reiserfs_export_ops;
15611da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
15621da177e4SLinus Torvalds 	s->s_qcop = &reiserfs_qctl_operations;
15631da177e4SLinus Torvalds 	s->dq_op = &reiserfs_quota_operations;
15641da177e4SLinus Torvalds #endif
15651da177e4SLinus Torvalds 
15661da177e4SLinus Torvalds 	/* new format is limited by the 32 bit wide i_blocks field, want to
15671da177e4SLinus Torvalds 	 ** be one full block below that.
15681da177e4SLinus Torvalds 	 */
15691da177e4SLinus Torvalds 	s->s_maxbytes = (512LL << 32) - s->s_blocksize;
15701da177e4SLinus Torvalds 	return 0;
15711da177e4SLinus Torvalds }
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds /* after journal replay, reread all bitmap and super blocks */
1574bd4c625cSLinus Torvalds static int reread_meta_blocks(struct super_block *s)
1575bd4c625cSLinus Torvalds {
15761da177e4SLinus Torvalds 	ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s)));
15771da177e4SLinus Torvalds 	wait_on_buffer(SB_BUFFER_WITH_SB(s));
15781da177e4SLinus Torvalds 	if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
157945b03d5eSJeff Mahoney 		reiserfs_warning(s, "reiserfs-2504", "error reading the super");
15801da177e4SLinus Torvalds 		return 1;
15811da177e4SLinus Torvalds 	}
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds 	return 0;
15841da177e4SLinus Torvalds }
15851da177e4SLinus Torvalds 
15861da177e4SLinus Torvalds /////////////////////////////////////////////////////
15871da177e4SLinus Torvalds // hash detection stuff
15881da177e4SLinus Torvalds 
15891da177e4SLinus Torvalds // if root directory is empty - we set default - Yura's - hash and
15901da177e4SLinus Torvalds // warn about it
15911da177e4SLinus Torvalds // FIXME: we look for only one name in a directory. If tea and yura
15921da177e4SLinus Torvalds // bith have the same value - we ask user to send report to the
15931da177e4SLinus Torvalds // mailing list
15941da177e4SLinus Torvalds static __u32 find_hash_out(struct super_block *s)
15951da177e4SLinus Torvalds {
15961da177e4SLinus Torvalds 	int retval;
15971da177e4SLinus Torvalds 	struct inode *inode;
15981da177e4SLinus Torvalds 	struct cpu_key key;
15991da177e4SLinus Torvalds 	INITIALIZE_PATH(path);
16001da177e4SLinus Torvalds 	struct reiserfs_dir_entry de;
16011da177e4SLinus Torvalds 	__u32 hash = DEFAULT_HASH;
16021da177e4SLinus Torvalds 
16031da177e4SLinus Torvalds 	inode = s->s_root->d_inode;
16041da177e4SLinus Torvalds 
16051da177e4SLinus Torvalds 	do {			// Some serious "goto"-hater was there ;)
16061da177e4SLinus Torvalds 		u32 teahash, r5hash, yurahash;
16071da177e4SLinus Torvalds 
16081da177e4SLinus Torvalds 		make_cpu_key(&key, inode, ~0, TYPE_DIRENTRY, 3);
16091da177e4SLinus Torvalds 		retval = search_by_entry_key(s, &key, &path, &de);
16101da177e4SLinus Torvalds 		if (retval == IO_ERROR) {
16111da177e4SLinus Torvalds 			pathrelse(&path);
16121da177e4SLinus Torvalds 			return UNSET_HASH;
16131da177e4SLinus Torvalds 		}
16141da177e4SLinus Torvalds 		if (retval == NAME_NOT_FOUND)
16151da177e4SLinus Torvalds 			de.de_entry_num--;
16161da177e4SLinus Torvalds 		set_de_name_and_namelen(&de);
16171da177e4SLinus Torvalds 		if (deh_offset(&(de.de_deh[de.de_entry_num])) == DOT_DOT_OFFSET) {
16181da177e4SLinus Torvalds 			/* allow override in this case */
16191da177e4SLinus Torvalds 			if (reiserfs_rupasov_hash(s)) {
16201da177e4SLinus Torvalds 				hash = YURA_HASH;
16211da177e4SLinus Torvalds 			}
16221d889d99SJeff Mahoney 			reiserfs_info(s, "FS seems to be empty, autodetect "
16231d889d99SJeff Mahoney 					 "is using the default hash\n");
16241da177e4SLinus Torvalds 			break;
16251da177e4SLinus Torvalds 		}
16261da177e4SLinus Torvalds 		r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen));
16271da177e4SLinus Torvalds 		teahash = GET_HASH_VALUE(keyed_hash(de.de_name, de.de_namelen));
16281da177e4SLinus Torvalds 		yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen));
1629bd4c625cSLinus Torvalds 		if (((teahash == r5hash)
1630bd4c625cSLinus Torvalds 		     &&
1631bd4c625cSLinus Torvalds 		     (GET_HASH_VALUE(deh_offset(&(de.de_deh[de.de_entry_num])))
1632bd4c625cSLinus Torvalds 		      == r5hash)) || ((teahash == yurahash)
1633bd4c625cSLinus Torvalds 				      && (yurahash ==
1634bd4c625cSLinus Torvalds 					  GET_HASH_VALUE(deh_offset
1635bd4c625cSLinus Torvalds 							 (&
1636bd4c625cSLinus Torvalds 							  (de.
1637bd4c625cSLinus Torvalds 							   de_deh[de.
1638bd4c625cSLinus Torvalds 								  de_entry_num])))))
1639bd4c625cSLinus Torvalds 		    || ((r5hash == yurahash)
1640bd4c625cSLinus Torvalds 			&& (yurahash ==
1641bd4c625cSLinus Torvalds 			    GET_HASH_VALUE(deh_offset
1642bd4c625cSLinus Torvalds 					   (&(de.de_deh[de.de_entry_num])))))) {
164345b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2506", "Unable to "
164445b03d5eSJeff Mahoney 					 "automatically detect hash function. "
164545b03d5eSJeff Mahoney 					 "Please mount with -o "
164645b03d5eSJeff Mahoney 					 "hash={tea,rupasov,r5}");
16471da177e4SLinus Torvalds 			hash = UNSET_HASH;
16481da177e4SLinus Torvalds 			break;
16491da177e4SLinus Torvalds 		}
1650bd4c625cSLinus Torvalds 		if (GET_HASH_VALUE(deh_offset(&(de.de_deh[de.de_entry_num]))) ==
1651bd4c625cSLinus Torvalds 		    yurahash)
16521da177e4SLinus Torvalds 			hash = YURA_HASH;
1653bd4c625cSLinus Torvalds 		else if (GET_HASH_VALUE
1654bd4c625cSLinus Torvalds 			 (deh_offset(&(de.de_deh[de.de_entry_num]))) == teahash)
16551da177e4SLinus Torvalds 			hash = TEA_HASH;
1656bd4c625cSLinus Torvalds 		else if (GET_HASH_VALUE
1657bd4c625cSLinus Torvalds 			 (deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash)
16581da177e4SLinus Torvalds 			hash = R5_HASH;
16591da177e4SLinus Torvalds 		else {
166045b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2506",
166145b03d5eSJeff Mahoney 					 "Unrecognised hash function");
16621da177e4SLinus Torvalds 			hash = UNSET_HASH;
16631da177e4SLinus Torvalds 		}
16641da177e4SLinus Torvalds 	} while (0);
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds 	pathrelse(&path);
16671da177e4SLinus Torvalds 	return hash;
16681da177e4SLinus Torvalds }
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds // finds out which hash names are sorted with
16711da177e4SLinus Torvalds static int what_hash(struct super_block *s)
16721da177e4SLinus Torvalds {
16731da177e4SLinus Torvalds 	__u32 code;
16741da177e4SLinus Torvalds 
16751da177e4SLinus Torvalds 	code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(s));
16761da177e4SLinus Torvalds 
16771da177e4SLinus Torvalds 	/* reiserfs_hash_detect() == true if any of the hash mount options
16781da177e4SLinus Torvalds 	 ** were used.  We must check them to make sure the user isn't
16791da177e4SLinus Torvalds 	 ** using a bad hash value
16801da177e4SLinus Torvalds 	 */
16811da177e4SLinus Torvalds 	if (code == UNSET_HASH || reiserfs_hash_detect(s))
16821da177e4SLinus Torvalds 		code = find_hash_out(s);
16831da177e4SLinus Torvalds 
16841da177e4SLinus Torvalds 	if (code != UNSET_HASH && reiserfs_hash_detect(s)) {
16851da177e4SLinus Torvalds 		/* detection has found the hash, and we must check against the
16861da177e4SLinus Torvalds 		 ** mount options
16871da177e4SLinus Torvalds 		 */
16881da177e4SLinus Torvalds 		if (reiserfs_rupasov_hash(s) && code != YURA_HASH) {
168945b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2507",
169045b03d5eSJeff Mahoney 					 "Error, %s hash detected, "
1691bd4c625cSLinus Torvalds 					 "unable to force rupasov hash",
1692bd4c625cSLinus Torvalds 					 reiserfs_hashname(code));
16931da177e4SLinus Torvalds 			code = UNSET_HASH;
16941da177e4SLinus Torvalds 		} else if (reiserfs_tea_hash(s) && code != TEA_HASH) {
169545b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2508",
169645b03d5eSJeff Mahoney 					 "Error, %s hash detected, "
1697bd4c625cSLinus Torvalds 					 "unable to force tea hash",
1698bd4c625cSLinus Torvalds 					 reiserfs_hashname(code));
16991da177e4SLinus Torvalds 			code = UNSET_HASH;
17001da177e4SLinus Torvalds 		} else if (reiserfs_r5_hash(s) && code != R5_HASH) {
170145b03d5eSJeff Mahoney 			reiserfs_warning(s, "reiserfs-2509",
170245b03d5eSJeff Mahoney 					 "Error, %s hash detected, "
1703bd4c625cSLinus Torvalds 					 "unable to force r5 hash",
1704bd4c625cSLinus Torvalds 					 reiserfs_hashname(code));
17051da177e4SLinus Torvalds 			code = UNSET_HASH;
17061da177e4SLinus Torvalds 		}
17071da177e4SLinus Torvalds 	} else {
17081da177e4SLinus Torvalds 		/* find_hash_out was not called or could not determine the hash */
17091da177e4SLinus Torvalds 		if (reiserfs_rupasov_hash(s)) {
17101da177e4SLinus Torvalds 			code = YURA_HASH;
17111da177e4SLinus Torvalds 		} else if (reiserfs_tea_hash(s)) {
17121da177e4SLinus Torvalds 			code = TEA_HASH;
17131da177e4SLinus Torvalds 		} else if (reiserfs_r5_hash(s)) {
17141da177e4SLinus Torvalds 			code = R5_HASH;
17151da177e4SLinus Torvalds 		}
17161da177e4SLinus Torvalds 	}
17171da177e4SLinus Torvalds 
17181da177e4SLinus Torvalds 	/* if we are mounted RW, and we have a new valid hash code, update
17191da177e4SLinus Torvalds 	 ** the super
17201da177e4SLinus Torvalds 	 */
17211da177e4SLinus Torvalds 	if (code != UNSET_HASH &&
17221da177e4SLinus Torvalds 	    !(s->s_flags & MS_RDONLY) &&
17231da177e4SLinus Torvalds 	    code != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) {
17241da177e4SLinus Torvalds 		set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code);
17251da177e4SLinus Torvalds 	}
17261da177e4SLinus Torvalds 	return code;
17271da177e4SLinus Torvalds }
17281da177e4SLinus Torvalds 
17291da177e4SLinus Torvalds // return pointer to appropriate function
17301da177e4SLinus Torvalds static hashf_t hash_function(struct super_block *s)
17311da177e4SLinus Torvalds {
17321da177e4SLinus Torvalds 	switch (what_hash(s)) {
17331da177e4SLinus Torvalds 	case TEA_HASH:
17341da177e4SLinus Torvalds 		reiserfs_info(s, "Using tea hash to sort names\n");
17351da177e4SLinus Torvalds 		return keyed_hash;
17361da177e4SLinus Torvalds 	case YURA_HASH:
17371da177e4SLinus Torvalds 		reiserfs_info(s, "Using rupasov hash to sort names\n");
17381da177e4SLinus Torvalds 		return yura_hash;
17391da177e4SLinus Torvalds 	case R5_HASH:
17401da177e4SLinus Torvalds 		reiserfs_info(s, "Using r5 hash to sort names\n");
17411da177e4SLinus Torvalds 		return r5_hash;
17421da177e4SLinus Torvalds 	}
17431da177e4SLinus Torvalds 	return NULL;
17441da177e4SLinus Torvalds }
17451da177e4SLinus Torvalds 
17461da177e4SLinus Torvalds // this is used to set up correct value for old partitions
17471da177e4SLinus Torvalds static int function2code(hashf_t func)
17481da177e4SLinus Torvalds {
17491da177e4SLinus Torvalds 	if (func == keyed_hash)
17501da177e4SLinus Torvalds 		return TEA_HASH;
17511da177e4SLinus Torvalds 	if (func == yura_hash)
17521da177e4SLinus Torvalds 		return YURA_HASH;
17531da177e4SLinus Torvalds 	if (func == r5_hash)
17541da177e4SLinus Torvalds 		return R5_HASH;
17551da177e4SLinus Torvalds 
17561da177e4SLinus Torvalds 	BUG();			// should never happen
17571da177e4SLinus Torvalds 
17581da177e4SLinus Torvalds 	return 0;
17591da177e4SLinus Torvalds }
17601da177e4SLinus Torvalds 
176145b03d5eSJeff Mahoney #define SWARN(silent, s, id, ...)			\
17621da177e4SLinus Torvalds 	if (!(silent))				\
176345b03d5eSJeff Mahoney 		reiserfs_warning(s, id, __VA_ARGS__)
17641da177e4SLinus Torvalds 
17651da177e4SLinus Torvalds static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
17661da177e4SLinus Torvalds {
17671da177e4SLinus Torvalds 	struct inode *root_inode;
17681da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
17691da177e4SLinus Torvalds 	int old_format = 0;
17701da177e4SLinus Torvalds 	unsigned long blocks;
17711da177e4SLinus Torvalds 	unsigned int commit_max_age = 0;
17721da177e4SLinus Torvalds 	int jinit_done = 0;
17731da177e4SLinus Torvalds 	struct reiserfs_iget_args args;
17741da177e4SLinus Torvalds 	struct reiserfs_super_block *rs;
17751da177e4SLinus Torvalds 	char *jdev_name;
17761da177e4SLinus Torvalds 	struct reiserfs_sb_info *sbi;
17771da177e4SLinus Torvalds 	int errval = -EINVAL;
177800b44197SJan Kara 	char *qf_names[MAXQUOTAS] = {};
177900b44197SJan Kara 	unsigned int qfmt = 0;
17801da177e4SLinus Torvalds 
1781cdf6ccc8SMiklos Szeredi 	save_mount_options(s, data);
1782cdf6ccc8SMiklos Szeredi 
178301afb213SYan Burman 	sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL);
1784b7b7fa43SJeff Mahoney 	if (!sbi)
1785b7b7fa43SJeff Mahoney 		return -ENOMEM;
17861da177e4SLinus Torvalds 	s->s_fs_info = sbi;
17871da177e4SLinus Torvalds 	/* Set default values for options: non-aggressive tails, RO on errors */
1788efaa33ebSArtem Bityutskiy 	sbi->s_mount_opt |= (1 << REISERFS_SMALLTAIL);
1789efaa33ebSArtem Bityutskiy 	sbi->s_mount_opt |= (1 << REISERFS_ERROR_RO);
1790efaa33ebSArtem Bityutskiy 	sbi->s_mount_opt |= (1 << REISERFS_BARRIER_FLUSH);
17911da177e4SLinus Torvalds 	/* no preallocation minimum, be smart in
17921da177e4SLinus Torvalds 	   reiserfs_file_write instead */
1793efaa33ebSArtem Bityutskiy 	sbi->s_alloc_options.preallocmin = 0;
17941da177e4SLinus Torvalds 	/* Preallocate by 16 blocks (17-1) at once */
1795efaa33ebSArtem Bityutskiy 	sbi->s_alloc_options.preallocsize = 17;
17961da177e4SLinus Torvalds 	/* setup default block allocator options */
17971da177e4SLinus Torvalds 	reiserfs_init_alloc_options(s);
17981da177e4SLinus Torvalds 
1799033369d1SArtem Bityutskiy 	spin_lock_init(&sbi->old_work_lock);
1800033369d1SArtem Bityutskiy 	INIT_DELAYED_WORK(&sbi->old_work, flush_old_commits);
1801efaa33ebSArtem Bityutskiy 	mutex_init(&sbi->lock);
1802efaa33ebSArtem Bityutskiy 	sbi->lock_depth = -1;
18038ebc4232SFrederic Weisbecker 
18041da177e4SLinus Torvalds 	jdev_name = NULL;
1805bd4c625cSLinus Torvalds 	if (reiserfs_parse_options
1806bd4c625cSLinus Torvalds 	    (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name,
180700b44197SJan Kara 	     &commit_max_age, qf_names, &qfmt) == 0) {
1808f32485beSFrederic Weisbecker 		goto error_unlocked;
18091da177e4SLinus Torvalds 	}
1810c3aa0776SJan Kara 	if (jdev_name && jdev_name[0]) {
1811efaa33ebSArtem Bityutskiy 		sbi->s_jdev = kstrdup(jdev_name, GFP_KERNEL);
1812efaa33ebSArtem Bityutskiy 		if (!sbi->s_jdev) {
1813c3aa0776SJan Kara 			SWARN(silent, s, "", "Cannot allocate memory for "
1814c3aa0776SJan Kara 				"journal device name");
1815c3aa0776SJan Kara 			goto error;
1816c3aa0776SJan Kara 		}
1817c3aa0776SJan Kara 	}
181800b44197SJan Kara #ifdef CONFIG_QUOTA
181900b44197SJan Kara 	handle_quota_files(s, qf_names, &qfmt);
182000b44197SJan Kara #endif
18211da177e4SLinus Torvalds 
18221da177e4SLinus Torvalds 	if (blocks) {
182345b03d5eSJeff Mahoney 		SWARN(silent, s, "jmacd-7", "resize option for remount only");
1824f32485beSFrederic Weisbecker 		goto error_unlocked;
18251da177e4SLinus Torvalds 	}
18261da177e4SLinus Torvalds 
18271da177e4SLinus Torvalds 	/* try old format (undistributed bitmap, super block in 8-th 1k block of a device) */
18281da177e4SLinus Torvalds 	if (!read_super_block(s, REISERFS_OLD_DISK_OFFSET_IN_BYTES))
18291da177e4SLinus Torvalds 		old_format = 1;
18301da177e4SLinus Torvalds 	/* try new format (64-th 1k block), which can contain reiserfs super block */
18311da177e4SLinus Torvalds 	else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) {
183245b03d5eSJeff Mahoney 		SWARN(silent, s, "sh-2021", "can not find reiserfs on %s",
1833bd4c625cSLinus Torvalds 		      reiserfs_bdevname(s));
1834f32485beSFrederic Weisbecker 		goto error_unlocked;
18351da177e4SLinus Torvalds 	}
18361da177e4SLinus Torvalds 
18371da177e4SLinus Torvalds 	rs = SB_DISK_SUPER_BLOCK(s);
18381da177e4SLinus Torvalds 	/* Let's do basic sanity check to verify that underlying device is not
18391da177e4SLinus Torvalds 	   smaller than the filesystem. If the check fails then abort and scream,
18401da177e4SLinus Torvalds 	   because bad stuff will happen otherwise. */
1841bd4c625cSLinus Torvalds 	if (s->s_bdev && s->s_bdev->bd_inode
1842bd4c625cSLinus Torvalds 	    && i_size_read(s->s_bdev->bd_inode) <
1843bd4c625cSLinus Torvalds 	    sb_block_count(rs) * sb_blocksize(rs)) {
184445b03d5eSJeff Mahoney 		SWARN(silent, s, "", "Filesystem cannot be "
184545b03d5eSJeff Mahoney 		      "mounted because it is bigger than the device");
184645b03d5eSJeff Mahoney 		SWARN(silent, s, "", "You may need to run fsck "
184745b03d5eSJeff Mahoney 		      "or increase size of your LVM partition");
184845b03d5eSJeff Mahoney 		SWARN(silent, s, "", "Or may be you forgot to "
184945b03d5eSJeff Mahoney 		      "reboot after fdisk when it told you to");
1850f32485beSFrederic Weisbecker 		goto error_unlocked;
18511da177e4SLinus Torvalds 	}
18521da177e4SLinus Torvalds 
18531da177e4SLinus Torvalds 	sbi->s_mount_state = SB_REISERFS_STATE(s);
18541da177e4SLinus Torvalds 	sbi->s_mount_state = REISERFS_VALID_FS;
18551da177e4SLinus Torvalds 
18566f01046bSJeff Mahoney 	if ((errval = reiserfs_init_bitmap_cache(s))) {
185745b03d5eSJeff Mahoney 		SWARN(silent, s, "jmacd-8", "unable to read bitmap");
1858f32485beSFrederic Weisbecker 		goto error_unlocked;
18591da177e4SLinus Torvalds 	}
1860f32485beSFrederic Weisbecker 
1861d2c89a42SJeff Mahoney 	errval = -EINVAL;
18621da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
186345b03d5eSJeff Mahoney 	SWARN(silent, s, "", "CONFIG_REISERFS_CHECK is set ON");
186445b03d5eSJeff Mahoney 	SWARN(silent, s, "", "- it is slow mode for debugging.");
18651da177e4SLinus Torvalds #endif
18661da177e4SLinus Torvalds 
18671da177e4SLinus Torvalds 	/* make data=ordered the default */
18681da177e4SLinus Torvalds 	if (!reiserfs_data_log(s) && !reiserfs_data_ordered(s) &&
1869bd4c625cSLinus Torvalds 	    !reiserfs_data_writeback(s)) {
1870efaa33ebSArtem Bityutskiy 		sbi->s_mount_opt |= (1 << REISERFS_DATA_ORDERED);
18711da177e4SLinus Torvalds 	}
18721da177e4SLinus Torvalds 
18731da177e4SLinus Torvalds 	if (reiserfs_data_log(s)) {
18741da177e4SLinus Torvalds 		reiserfs_info(s, "using journaled data mode\n");
18751da177e4SLinus Torvalds 	} else if (reiserfs_data_ordered(s)) {
18761da177e4SLinus Torvalds 		reiserfs_info(s, "using ordered data mode\n");
18771da177e4SLinus Torvalds 	} else {
18781da177e4SLinus Torvalds 		reiserfs_info(s, "using writeback data mode\n");
18791da177e4SLinus Torvalds 	}
18801da177e4SLinus Torvalds 	if (reiserfs_barrier_flush(s)) {
18811da177e4SLinus Torvalds 		printk("reiserfs: using flush barriers\n");
18821da177e4SLinus Torvalds 	}
1883f32485beSFrederic Weisbecker 
188437c69b98SFrederic Weisbecker 	// set_device_ro(s->s_dev, 1) ;
188537c69b98SFrederic Weisbecker 	if (journal_init(s, jdev_name, old_format, commit_max_age)) {
188637c69b98SFrederic Weisbecker 		SWARN(silent, s, "sh-2022",
188737c69b98SFrederic Weisbecker 		      "unable to initialize journal space");
188837c69b98SFrederic Weisbecker 		goto error_unlocked;
188937c69b98SFrederic Weisbecker 	} else {
189037c69b98SFrederic Weisbecker 		jinit_done = 1;	/* once this is set, journal_release must be called
189137c69b98SFrederic Weisbecker 				 ** if we error out of the mount
189237c69b98SFrederic Weisbecker 				 */
189337c69b98SFrederic Weisbecker 	}
189437c69b98SFrederic Weisbecker 
18951da177e4SLinus Torvalds 	if (reread_meta_blocks(s)) {
189645b03d5eSJeff Mahoney 		SWARN(silent, s, "jmacd-9",
189745b03d5eSJeff Mahoney 		      "unable to reread meta blocks after journal init");
18989b467e6eSFrederic Weisbecker 		goto error_unlocked;
18991da177e4SLinus Torvalds 	}
19001da177e4SLinus Torvalds 
19011da177e4SLinus Torvalds 	if (replay_only(s))
19029b467e6eSFrederic Weisbecker 		goto error_unlocked;
19031da177e4SLinus Torvalds 
19041da177e4SLinus Torvalds 	if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) {
190545b03d5eSJeff Mahoney 		SWARN(silent, s, "clm-7000",
190645b03d5eSJeff Mahoney 		      "Detected readonly device, marking FS readonly");
19071da177e4SLinus Torvalds 		s->s_flags |= MS_RDONLY;
19081da177e4SLinus Torvalds 	}
19091da177e4SLinus Torvalds 	args.objectid = REISERFS_ROOT_OBJECTID;
19101da177e4SLinus Torvalds 	args.dirid = REISERFS_ROOT_PARENT_OBJECTID;
1911bd4c625cSLinus Torvalds 	root_inode =
1912bd4c625cSLinus Torvalds 	    iget5_locked(s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor,
1913bd4c625cSLinus Torvalds 			 reiserfs_init_locked_inode, (void *)(&args));
19141da177e4SLinus Torvalds 	if (!root_inode) {
191545b03d5eSJeff Mahoney 		SWARN(silent, s, "jmacd-10", "get root inode failed");
19169b467e6eSFrederic Weisbecker 		goto error_unlocked;
19171da177e4SLinus Torvalds 	}
19181da177e4SLinus Torvalds 
19199b467e6eSFrederic Weisbecker 	/*
19209b467e6eSFrederic Weisbecker 	 * This path assumed to be called with the BKL in the old times.
19219b467e6eSFrederic Weisbecker 	 * Now we have inherited the big reiserfs lock from it and many
19229b467e6eSFrederic Weisbecker 	 * reiserfs helpers called in the mount path and elsewhere require
19239b467e6eSFrederic Weisbecker 	 * this lock to be held even if it's not always necessary. Let's be
19249b467e6eSFrederic Weisbecker 	 * conservative and hold it early. The window can be reduced after
19259b467e6eSFrederic Weisbecker 	 * careful review of the code.
19269b467e6eSFrederic Weisbecker 	 */
19279b467e6eSFrederic Weisbecker 	reiserfs_write_lock(s);
19289b467e6eSFrederic Weisbecker 
19291da177e4SLinus Torvalds 	if (root_inode->i_state & I_NEW) {
19301da177e4SLinus Torvalds 		reiserfs_read_locked_inode(root_inode, &args);
19311da177e4SLinus Torvalds 		unlock_new_inode(root_inode);
19321da177e4SLinus Torvalds 	}
19331da177e4SLinus Torvalds 
193448fde701SAl Viro 	s->s_root = d_make_root(root_inode);
193548fde701SAl Viro 	if (!s->s_root)
19361da177e4SLinus Torvalds 		goto error;
19371da177e4SLinus Torvalds 	// define and initialize hash function
19381da177e4SLinus Torvalds 	sbi->s_hash_function = hash_function(s);
19391da177e4SLinus Torvalds 	if (sbi->s_hash_function == NULL) {
19401da177e4SLinus Torvalds 		dput(s->s_root);
19411da177e4SLinus Torvalds 		s->s_root = NULL;
19421da177e4SLinus Torvalds 		goto error;
19431da177e4SLinus Torvalds 	}
19441da177e4SLinus Torvalds 
1945bd4c625cSLinus Torvalds 	if (is_reiserfs_3_5(rs)
1946bd4c625cSLinus Torvalds 	    || (is_reiserfs_jr(rs) && SB_VERSION(s) == REISERFS_VERSION_1))
19471da177e4SLinus Torvalds 		set_bit(REISERFS_3_5, &(sbi->s_properties));
1948e1fabd3cSJeff Mahoney 	else if (old_format)
1949e1fabd3cSJeff Mahoney 		set_bit(REISERFS_OLD_FORMAT, &(sbi->s_properties));
19501da177e4SLinus Torvalds 	else
19511da177e4SLinus Torvalds 		set_bit(REISERFS_3_6, &(sbi->s_properties));
19521da177e4SLinus Torvalds 
19531da177e4SLinus Torvalds 	if (!(s->s_flags & MS_RDONLY)) {
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds 		errval = journal_begin(&th, s, 1);
19561da177e4SLinus Torvalds 		if (errval) {
19571da177e4SLinus Torvalds 			dput(s->s_root);
19581da177e4SLinus Torvalds 			s->s_root = NULL;
19591da177e4SLinus Torvalds 			goto error;
19601da177e4SLinus Torvalds 		}
19611da177e4SLinus Torvalds 		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
19621da177e4SLinus Torvalds 
19631da177e4SLinus Torvalds 		set_sb_umount_state(rs, REISERFS_ERROR_FS);
19641da177e4SLinus Torvalds 		set_sb_fs_state(rs, 0);
19651da177e4SLinus Torvalds 
1966cb680c1bSJeff Mahoney 		/* Clear out s_bmap_nr if it would wrap. We can handle this
1967cb680c1bSJeff Mahoney 		 * case, but older revisions can't. This will cause the
1968cb680c1bSJeff Mahoney 		 * file system to fail mount on those older implementations,
1969cb680c1bSJeff Mahoney 		 * avoiding corruption. -jeffm */
1970cb680c1bSJeff Mahoney 		if (bmap_would_wrap(reiserfs_bmap_count(s)) &&
1971cb680c1bSJeff Mahoney 		    sb_bmap_nr(rs) != 0) {
197245b03d5eSJeff Mahoney 			reiserfs_warning(s, "super-2030", "This file system "
1973cb680c1bSJeff Mahoney 					"claims to use %u bitmap blocks in "
1974cb680c1bSJeff Mahoney 					"its super block, but requires %u. "
1975cb680c1bSJeff Mahoney 					"Clearing to zero.", sb_bmap_nr(rs),
1976cb680c1bSJeff Mahoney 					reiserfs_bmap_count(s));
1977cb680c1bSJeff Mahoney 
1978cb680c1bSJeff Mahoney 			set_sb_bmap_nr(rs, 0);
1979cb680c1bSJeff Mahoney 		}
1980cb680c1bSJeff Mahoney 
19811da177e4SLinus Torvalds 		if (old_format_only(s)) {
19821da177e4SLinus Torvalds 			/* filesystem of format 3.5 either with standard or non-standard
19831da177e4SLinus Torvalds 			   journal */
19841da177e4SLinus Torvalds 			if (convert_reiserfs(s)) {
19851da177e4SLinus Torvalds 				/* and -o conv is given */
19861da177e4SLinus Torvalds 				if (!silent)
1987bd4c625cSLinus Torvalds 					reiserfs_info(s,
1988bd4c625cSLinus Torvalds 						      "converting 3.5 filesystem to the 3.6 format");
19891da177e4SLinus Torvalds 
19901da177e4SLinus Torvalds 				if (is_reiserfs_3_5(rs))
19911da177e4SLinus Torvalds 					/* put magic string of 3.6 format. 2.2 will not be able to
19921da177e4SLinus Torvalds 					   mount this filesystem anymore */
1993bd4c625cSLinus Torvalds 					memcpy(rs->s_v1.s_magic,
1994bd4c625cSLinus Torvalds 					       reiserfs_3_6_magic_string,
1995bd4c625cSLinus Torvalds 					       sizeof
1996bd4c625cSLinus Torvalds 					       (reiserfs_3_6_magic_string));
19971da177e4SLinus Torvalds 
19981da177e4SLinus Torvalds 				set_sb_version(rs, REISERFS_VERSION_2);
19991da177e4SLinus Torvalds 				reiserfs_convert_objectid_map_v1(s);
20001da177e4SLinus Torvalds 				set_bit(REISERFS_3_6, &(sbi->s_properties));
20011da177e4SLinus Torvalds 				clear_bit(REISERFS_3_5, &(sbi->s_properties));
20021da177e4SLinus Torvalds 			} else if (!silent) {
20031da177e4SLinus Torvalds 				reiserfs_info(s, "using 3.5.x disk format\n");
20041da177e4SLinus Torvalds 			}
2005702d21c6SJeff Mahoney 		} else
2006702d21c6SJeff Mahoney 			set_sb_mnt_count(rs, sb_mnt_count(rs) + 1);
2007702d21c6SJeff Mahoney 
20081da177e4SLinus Torvalds 
20091da177e4SLinus Torvalds 		journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
20101da177e4SLinus Torvalds 		errval = journal_end(&th, s, 1);
20111da177e4SLinus Torvalds 		if (errval) {
20121da177e4SLinus Torvalds 			dput(s->s_root);
20131da177e4SLinus Torvalds 			s->s_root = NULL;
20141da177e4SLinus Torvalds 			goto error;
20151da177e4SLinus Torvalds 		}
20161da177e4SLinus Torvalds 
2017edcc37a0SAl Viro 		if ((errval = reiserfs_lookup_privroot(s)) ||
2018edcc37a0SAl Viro 		    (errval = reiserfs_xattr_init(s, s->s_flags))) {
20191da177e4SLinus Torvalds 			dput(s->s_root);
20201da177e4SLinus Torvalds 			s->s_root = NULL;
20211da177e4SLinus Torvalds 			goto error;
20221da177e4SLinus Torvalds 		}
20231da177e4SLinus Torvalds 
20241da177e4SLinus Torvalds 		/* look for files which were to be removed in previous session */
20251da177e4SLinus Torvalds 		finish_unfinished(s);
20261da177e4SLinus Torvalds 	} else {
20271da177e4SLinus Torvalds 		if (old_format_only(s) && !silent) {
20281da177e4SLinus Torvalds 			reiserfs_info(s, "using 3.5.x disk format\n");
20291da177e4SLinus Torvalds 		}
20301da177e4SLinus Torvalds 
2031edcc37a0SAl Viro 		if ((errval = reiserfs_lookup_privroot(s)) ||
2032edcc37a0SAl Viro 		    (errval = reiserfs_xattr_init(s, s->s_flags))) {
20331da177e4SLinus Torvalds 			dput(s->s_root);
20341da177e4SLinus Torvalds 			s->s_root = NULL;
20351da177e4SLinus Torvalds 			goto error;
20361da177e4SLinus Torvalds 		}
20371da177e4SLinus Torvalds 	}
20381da177e4SLinus Torvalds 	// mark hash in super block: it could be unset. overwrite should be ok
20391da177e4SLinus Torvalds 	set_sb_hash_function_code(rs, function2code(sbi->s_hash_function));
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 	handle_attrs(s);
20421da177e4SLinus Torvalds 
20431da177e4SLinus Torvalds 	reiserfs_proc_info_init(s);
20441da177e4SLinus Torvalds 
20451da177e4SLinus Torvalds 	init_waitqueue_head(&(sbi->s_wait));
20461da177e4SLinus Torvalds 	spin_lock_init(&sbi->bitmap_lock);
20471da177e4SLinus Torvalds 
20488ebc4232SFrederic Weisbecker 	reiserfs_write_unlock(s);
20498ebc4232SFrederic Weisbecker 
20501da177e4SLinus Torvalds 	return (0);
20511da177e4SLinus Torvalds 
20521da177e4SLinus Torvalds error:
2053b7b7fa43SJeff Mahoney 	reiserfs_write_unlock(s);
2054b7b7fa43SJeff Mahoney 
2055f32485beSFrederic Weisbecker error_unlocked:
2056f32485beSFrederic Weisbecker 	/* kill the commit thread, free journal ram */
2057f32485beSFrederic Weisbecker 	if (jinit_done) {
2058f32485beSFrederic Weisbecker 		reiserfs_write_lock(s);
2059f32485beSFrederic Weisbecker 		journal_release_error(NULL, s);
2060f32485beSFrederic Weisbecker 		reiserfs_write_unlock(s);
2061f32485beSFrederic Weisbecker 	}
2062f32485beSFrederic Weisbecker 
2063033369d1SArtem Bityutskiy 	cancel_delayed_work_sync(&REISERFS_SB(s)->old_work);
2064033369d1SArtem Bityutskiy 
20655065227bSJeff Mahoney 	reiserfs_free_bitmap_cache(s);
20661da177e4SLinus Torvalds 	if (SB_BUFFER_WITH_SB(s))
20671da177e4SLinus Torvalds 		brelse(SB_BUFFER_WITH_SB(s));
20681da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
20695065227bSJeff Mahoney 	{
20705065227bSJeff Mahoney 		int j;
207100b44197SJan Kara 		for (j = 0; j < MAXQUOTAS; j++)
207200b44197SJan Kara 			kfree(qf_names[j]);
20735065227bSJeff Mahoney 	}
20741da177e4SLinus Torvalds #endif
20751da177e4SLinus Torvalds 	kfree(sbi);
20761da177e4SLinus Torvalds 
20771da177e4SLinus Torvalds 	s->s_fs_info = NULL;
20781da177e4SLinus Torvalds 	return errval;
20791da177e4SLinus Torvalds }
20801da177e4SLinus Torvalds 
2081726c3342SDavid Howells static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf)
20821da177e4SLinus Torvalds {
2083726c3342SDavid Howells 	struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(dentry->d_sb);
20841da177e4SLinus Torvalds 
20851da177e4SLinus Torvalds 	buf->f_namelen = (REISERFS_MAX_NAME(s->s_blocksize));
20861da177e4SLinus Torvalds 	buf->f_bfree = sb_free_blocks(rs);
20871da177e4SLinus Torvalds 	buf->f_bavail = buf->f_bfree;
20881da177e4SLinus Torvalds 	buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
2089726c3342SDavid Howells 	buf->f_bsize = dentry->d_sb->s_blocksize;
20901da177e4SLinus Torvalds 	/* changed to accommodate gcc folks. */
20911da177e4SLinus Torvalds 	buf->f_type = REISERFS_SUPER_MAGIC;
2092651d0623SColy Li 	buf->f_fsid.val[0] = (u32)crc32_le(0, rs->s_uuid, sizeof(rs->s_uuid)/2);
2093651d0623SColy Li 	buf->f_fsid.val[1] = (u32)crc32_le(0, rs->s_uuid + sizeof(rs->s_uuid)/2,
2094651d0623SColy Li 				sizeof(rs->s_uuid)/2);
2095651d0623SColy Li 
20961da177e4SLinus Torvalds 	return 0;
20971da177e4SLinus Torvalds }
20981da177e4SLinus Torvalds 
20991da177e4SLinus Torvalds #ifdef CONFIG_QUOTA
21001da177e4SLinus Torvalds static int reiserfs_write_dquot(struct dquot *dquot)
21011da177e4SLinus Torvalds {
21021da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
2103bd6a1f16SJan Kara 	int ret, err;
21041da177e4SLinus Torvalds 
21051da177e4SLinus Torvalds 	reiserfs_write_lock(dquot->dq_sb);
2106bd4c625cSLinus Torvalds 	ret =
2107bd4c625cSLinus Torvalds 	    journal_begin(&th, dquot->dq_sb,
2108bd4c625cSLinus Torvalds 			  REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
2109bd6a1f16SJan Kara 	if (ret)
2110bd6a1f16SJan Kara 		goto out;
21111da177e4SLinus Torvalds 	ret = dquot_commit(dquot);
2112bd4c625cSLinus Torvalds 	err =
2113bd4c625cSLinus Torvalds 	    journal_end(&th, dquot->dq_sb,
2114bd4c625cSLinus Torvalds 			REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
2115bd6a1f16SJan Kara 	if (!ret && err)
2116bd6a1f16SJan Kara 		ret = err;
2117bd6a1f16SJan Kara       out:
21181da177e4SLinus Torvalds 	reiserfs_write_unlock(dquot->dq_sb);
21191da177e4SLinus Torvalds 	return ret;
21201da177e4SLinus Torvalds }
21211da177e4SLinus Torvalds 
21221da177e4SLinus Torvalds static int reiserfs_acquire_dquot(struct dquot *dquot)
21231da177e4SLinus Torvalds {
21241da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
2125bd6a1f16SJan Kara 	int ret, err;
21261da177e4SLinus Torvalds 
21271da177e4SLinus Torvalds 	reiserfs_write_lock(dquot->dq_sb);
2128bd4c625cSLinus Torvalds 	ret =
2129bd4c625cSLinus Torvalds 	    journal_begin(&th, dquot->dq_sb,
2130bd4c625cSLinus Torvalds 			  REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
2131bd6a1f16SJan Kara 	if (ret)
2132bd6a1f16SJan Kara 		goto out;
21331da177e4SLinus Torvalds 	ret = dquot_acquire(dquot);
2134bd4c625cSLinus Torvalds 	err =
2135bd4c625cSLinus Torvalds 	    journal_end(&th, dquot->dq_sb,
2136bd4c625cSLinus Torvalds 			REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
2137bd6a1f16SJan Kara 	if (!ret && err)
2138bd6a1f16SJan Kara 		ret = err;
2139bd6a1f16SJan Kara       out:
21401da177e4SLinus Torvalds 	reiserfs_write_unlock(dquot->dq_sb);
21411da177e4SLinus Torvalds 	return ret;
21421da177e4SLinus Torvalds }
21431da177e4SLinus Torvalds 
21441da177e4SLinus Torvalds static int reiserfs_release_dquot(struct dquot *dquot)
21451da177e4SLinus Torvalds {
21461da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
2147bd6a1f16SJan Kara 	int ret, err;
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds 	reiserfs_write_lock(dquot->dq_sb);
2150bd4c625cSLinus Torvalds 	ret =
2151bd4c625cSLinus Torvalds 	    journal_begin(&th, dquot->dq_sb,
2152bd4c625cSLinus Torvalds 			  REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
21539c3013e9SJan Kara 	if (ret) {
21549c3013e9SJan Kara 		/* Release dquot anyway to avoid endless cycle in dqput() */
21559c3013e9SJan Kara 		dquot_release(dquot);
2156bd6a1f16SJan Kara 		goto out;
21579c3013e9SJan Kara 	}
21581da177e4SLinus Torvalds 	ret = dquot_release(dquot);
2159bd4c625cSLinus Torvalds 	err =
2160bd4c625cSLinus Torvalds 	    journal_end(&th, dquot->dq_sb,
2161bd4c625cSLinus Torvalds 			REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
2162bd6a1f16SJan Kara 	if (!ret && err)
2163bd6a1f16SJan Kara 		ret = err;
2164bd6a1f16SJan Kara       out:
21651da177e4SLinus Torvalds 	reiserfs_write_unlock(dquot->dq_sb);
21661da177e4SLinus Torvalds 	return ret;
21671da177e4SLinus Torvalds }
21681da177e4SLinus Torvalds 
21691da177e4SLinus Torvalds static int reiserfs_mark_dquot_dirty(struct dquot *dquot)
21701da177e4SLinus Torvalds {
21714506567bSJan Kara 	/* Are we journaling quotas? */
21721da177e4SLinus Torvalds 	if (REISERFS_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] ||
21731da177e4SLinus Torvalds 	    REISERFS_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) {
21741da177e4SLinus Torvalds 		dquot_mark_dquot_dirty(dquot);
21751da177e4SLinus Torvalds 		return reiserfs_write_dquot(dquot);
2176bd4c625cSLinus Torvalds 	} else
21771da177e4SLinus Torvalds 		return dquot_mark_dquot_dirty(dquot);
21781da177e4SLinus Torvalds }
21791da177e4SLinus Torvalds 
21801da177e4SLinus Torvalds static int reiserfs_write_info(struct super_block *sb, int type)
21811da177e4SLinus Torvalds {
21821da177e4SLinus Torvalds 	struct reiserfs_transaction_handle th;
2183bd6a1f16SJan Kara 	int ret, err;
21841da177e4SLinus Torvalds 
21851da177e4SLinus Torvalds 	/* Data block + inode block */
21861da177e4SLinus Torvalds 	reiserfs_write_lock(sb);
2187bd6a1f16SJan Kara 	ret = journal_begin(&th, sb, 2);
2188bd6a1f16SJan Kara 	if (ret)
2189bd6a1f16SJan Kara 		goto out;
21901da177e4SLinus Torvalds 	ret = dquot_commit_info(sb, type);
2191bd6a1f16SJan Kara 	err = journal_end(&th, sb, 2);
2192bd6a1f16SJan Kara 	if (!ret && err)
2193bd6a1f16SJan Kara 		ret = err;
2194bd6a1f16SJan Kara       out:
21951da177e4SLinus Torvalds 	reiserfs_write_unlock(sb);
21961da177e4SLinus Torvalds 	return ret;
21971da177e4SLinus Torvalds }
21981da177e4SLinus Torvalds 
21991da177e4SLinus Torvalds /*
220084de856eSChristoph Hellwig  * Turn on quotas during mount time - we need to find the quota file and such...
22011da177e4SLinus Torvalds  */
22021da177e4SLinus Torvalds static int reiserfs_quota_on_mount(struct super_block *sb, int type)
22031da177e4SLinus Torvalds {
2204287a8095SChristoph Hellwig 	return dquot_quota_on_mount(sb, REISERFS_SB(sb)->s_qf_names[type],
220584de856eSChristoph Hellwig 					REISERFS_SB(sb)->s_jquota_fmt, type);
22061da177e4SLinus Torvalds }
22071da177e4SLinus Torvalds 
22081da177e4SLinus Torvalds /*
22091da177e4SLinus Torvalds  * Standard function to be called on quota_on
22101da177e4SLinus Torvalds  */
2211bd4c625cSLinus Torvalds static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
2212f00c9e44SJan Kara 			     struct path *path)
22131da177e4SLinus Torvalds {
22141da177e4SLinus Torvalds 	int err;
2215d5dee5c3SJan Kara 	struct inode *inode;
22165d4f7fddSJan Kara 	struct reiserfs_transaction_handle th;
2217c3aa0776SJan Kara 	int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA;
22181da177e4SLinus Torvalds 
2219c3aa0776SJan Kara 	if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt)))
2220556a2a45SJan Kara 		return -EINVAL;
2221307ae18aSChristoph Hellwig 
22221da177e4SLinus Torvalds 	/* Quotafile not on the same filesystem? */
2223d8c9584eSAl Viro 	if (path->dentry->d_sb != sb) {
222477e69dacSAl Viro 		err = -EXDEV;
222577e69dacSAl Viro 		goto out;
22261da177e4SLinus Torvalds 	}
2227f00c9e44SJan Kara 	inode = path->dentry->d_inode;
22281da177e4SLinus Torvalds 	/* We must not pack tails for quota files on reiserfs for quota IO to work */
2229d5dee5c3SJan Kara 	if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
2230d5dee5c3SJan Kara 		err = reiserfs_unpack(inode, NULL);
2231d5dee5c3SJan Kara 		if (err) {
223245b03d5eSJeff Mahoney 			reiserfs_warning(sb, "super-6520",
223345b03d5eSJeff Mahoney 				"Unpacking tail of quota file failed"
2234d5dee5c3SJan Kara 				" (%d). Cannot turn on quotas.", err);
223577e69dacSAl Viro 			err = -EINVAL;
223677e69dacSAl Viro 			goto out;
22371da177e4SLinus Torvalds 		}
2238d5dee5c3SJan Kara 		mark_inode_dirty(inode);
2239d5dee5c3SJan Kara 	}
22405d4f7fddSJan Kara 	/* Journaling quota? */
22415d4f7fddSJan Kara 	if (REISERFS_SB(sb)->s_qf_names[type]) {
22421da177e4SLinus Torvalds 		/* Quotafile not of fs root? */
2243f00c9e44SJan Kara 		if (path->dentry->d_parent != sb->s_root)
224445b03d5eSJeff Mahoney 			reiserfs_warning(sb, "super-6521",
224545b03d5eSJeff Mahoney 				 "Quota file not on filesystem root. "
22461da177e4SLinus Torvalds 				 "Journalled quota will not work.");
22475d4f7fddSJan Kara 	}
22485d4f7fddSJan Kara 
22495d4f7fddSJan Kara 	/*
22505d4f7fddSJan Kara 	 * When we journal data on quota file, we have to flush journal to see
22515d4f7fddSJan Kara 	 * all updates to the file when we bypass pagecache...
22525d4f7fddSJan Kara 	 */
22535d4f7fddSJan Kara 	if (reiserfs_file_data_log(inode)) {
22545d4f7fddSJan Kara 		/* Just start temporary transaction and finish it */
22555d4f7fddSJan Kara 		err = journal_begin(&th, sb, 1);
22565d4f7fddSJan Kara 		if (err)
225777e69dacSAl Viro 			goto out;
22585d4f7fddSJan Kara 		err = journal_end_sync(&th, sb, 1);
22595d4f7fddSJan Kara 		if (err)
226077e69dacSAl Viro 			goto out;
22615d4f7fddSJan Kara 	}
2262f00c9e44SJan Kara 	err = dquot_quota_on(sb, type, format_id, path);
226377e69dacSAl Viro out:
226477e69dacSAl Viro 	return err;
22651da177e4SLinus Torvalds }
22661da177e4SLinus Torvalds 
22671da177e4SLinus Torvalds /* Read data from quotafile - avoid pagecache and such because we cannot afford
22681da177e4SLinus Torvalds  * acquiring the locks... As quota files are never truncated and quota code
22691da177e4SLinus Torvalds  * itself serializes the operations (and no one else should touch the files)
22701da177e4SLinus Torvalds  * we don't have to be afraid of races */
22711da177e4SLinus Torvalds static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data,
22721da177e4SLinus Torvalds 				   size_t len, loff_t off)
22731da177e4SLinus Torvalds {
22741da177e4SLinus Torvalds 	struct inode *inode = sb_dqopt(sb)->files[type];
22751da177e4SLinus Torvalds 	unsigned long blk = off >> sb->s_blocksize_bits;
22761da177e4SLinus Torvalds 	int err = 0, offset = off & (sb->s_blocksize - 1), tocopy;
22771da177e4SLinus Torvalds 	size_t toread;
22781da177e4SLinus Torvalds 	struct buffer_head tmp_bh, *bh;
22791da177e4SLinus Torvalds 	loff_t i_size = i_size_read(inode);
22801da177e4SLinus Torvalds 
22811da177e4SLinus Torvalds 	if (off > i_size)
22821da177e4SLinus Torvalds 		return 0;
22831da177e4SLinus Torvalds 	if (off + len > i_size)
22841da177e4SLinus Torvalds 		len = i_size - off;
22851da177e4SLinus Torvalds 	toread = len;
22861da177e4SLinus Torvalds 	while (toread > 0) {
2287bd4c625cSLinus Torvalds 		tocopy =
2288bd4c625cSLinus Torvalds 		    sb->s_blocksize - offset <
2289bd4c625cSLinus Torvalds 		    toread ? sb->s_blocksize - offset : toread;
22901da177e4SLinus Torvalds 		tmp_bh.b_state = 0;
22911da177e4SLinus Torvalds 		/* Quota files are without tails so we can safely use this function */
22921da177e4SLinus Torvalds 		reiserfs_write_lock(sb);
22931da177e4SLinus Torvalds 		err = reiserfs_get_block(inode, blk, &tmp_bh, 0);
22941da177e4SLinus Torvalds 		reiserfs_write_unlock(sb);
22951da177e4SLinus Torvalds 		if (err)
22961da177e4SLinus Torvalds 			return err;
22971da177e4SLinus Torvalds 		if (!buffer_mapped(&tmp_bh))	/* A hole? */
22981da177e4SLinus Torvalds 			memset(data, 0, tocopy);
22991da177e4SLinus Torvalds 		else {
23001da177e4SLinus Torvalds 			bh = sb_bread(sb, tmp_bh.b_blocknr);
23011da177e4SLinus Torvalds 			if (!bh)
23021da177e4SLinus Torvalds 				return -EIO;
23031da177e4SLinus Torvalds 			memcpy(data, bh->b_data + offset, tocopy);
23041da177e4SLinus Torvalds 			brelse(bh);
23051da177e4SLinus Torvalds 		}
23061da177e4SLinus Torvalds 		offset = 0;
23071da177e4SLinus Torvalds 		toread -= tocopy;
23081da177e4SLinus Torvalds 		data += tocopy;
23091da177e4SLinus Torvalds 		blk++;
23101da177e4SLinus Torvalds 	}
23111da177e4SLinus Torvalds 	return len;
23121da177e4SLinus Torvalds }
23131da177e4SLinus Torvalds 
23141da177e4SLinus Torvalds /* Write to quotafile (we know the transaction is already started and has
23151da177e4SLinus Torvalds  * enough credits) */
23161da177e4SLinus Torvalds static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
23171da177e4SLinus Torvalds 				    const char *data, size_t len, loff_t off)
23181da177e4SLinus Torvalds {
23191da177e4SLinus Torvalds 	struct inode *inode = sb_dqopt(sb)->files[type];
23201da177e4SLinus Torvalds 	unsigned long blk = off >> sb->s_blocksize_bits;
23211da177e4SLinus Torvalds 	int err = 0, offset = off & (sb->s_blocksize - 1), tocopy;
23221da177e4SLinus Torvalds 	int journal_quota = REISERFS_SB(sb)->s_qf_names[type] != NULL;
23231da177e4SLinus Torvalds 	size_t towrite = len;
23241da177e4SLinus Torvalds 	struct buffer_head tmp_bh, *bh;
23251da177e4SLinus Torvalds 
23269c3013e9SJan Kara 	if (!current->journal_info) {
23279c3013e9SJan Kara 		printk(KERN_WARNING "reiserfs: Quota write (off=%Lu, len=%Lu)"
23289c3013e9SJan Kara 			" cancelled because transaction is not started.\n",
23299c3013e9SJan Kara 			(unsigned long long)off, (unsigned long long)len);
23309c3013e9SJan Kara 		return -EIO;
23319c3013e9SJan Kara 	}
23321da177e4SLinus Torvalds 	while (towrite > 0) {
23331da177e4SLinus Torvalds 		tocopy = sb->s_blocksize - offset < towrite ?
23341da177e4SLinus Torvalds 		    sb->s_blocksize - offset : towrite;
23351da177e4SLinus Torvalds 		tmp_bh.b_state = 0;
23361da177e4SLinus Torvalds 		err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE);
23371da177e4SLinus Torvalds 		if (err)
23381da177e4SLinus Torvalds 			goto out;
23391da177e4SLinus Torvalds 		if (offset || tocopy != sb->s_blocksize)
23401da177e4SLinus Torvalds 			bh = sb_bread(sb, tmp_bh.b_blocknr);
23411da177e4SLinus Torvalds 		else
23421da177e4SLinus Torvalds 			bh = sb_getblk(sb, tmp_bh.b_blocknr);
23431da177e4SLinus Torvalds 		if (!bh) {
23441da177e4SLinus Torvalds 			err = -EIO;
23451da177e4SLinus Torvalds 			goto out;
23461da177e4SLinus Torvalds 		}
23471da177e4SLinus Torvalds 		lock_buffer(bh);
23481da177e4SLinus Torvalds 		memcpy(bh->b_data + offset, data, tocopy);
23491da177e4SLinus Torvalds 		flush_dcache_page(bh->b_page);
23501da177e4SLinus Torvalds 		set_buffer_uptodate(bh);
23511da177e4SLinus Torvalds 		unlock_buffer(bh);
23521da177e4SLinus Torvalds 		reiserfs_prepare_for_journal(sb, bh, 1);
23531da177e4SLinus Torvalds 		journal_mark_dirty(current->journal_info, sb, bh);
23541da177e4SLinus Torvalds 		if (!journal_quota)
23551da177e4SLinus Torvalds 			reiserfs_add_ordered_list(inode, bh);
23561da177e4SLinus Torvalds 		brelse(bh);
23571da177e4SLinus Torvalds 		offset = 0;
23581da177e4SLinus Torvalds 		towrite -= tocopy;
23591da177e4SLinus Torvalds 		data += tocopy;
23601da177e4SLinus Torvalds 		blk++;
23611da177e4SLinus Torvalds 	}
23621da177e4SLinus Torvalds out:
236367f1648dSJan Kara 	if (len == towrite)
23641da177e4SLinus Torvalds 		return err;
23651da177e4SLinus Torvalds 	if (inode->i_size < off + len - towrite)
23661da177e4SLinus Torvalds 		i_size_write(inode, off + len - towrite);
23671da177e4SLinus Torvalds 	inode->i_version++;
23681da177e4SLinus Torvalds 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
23691da177e4SLinus Torvalds 	mark_inode_dirty(inode);
23701da177e4SLinus Torvalds 	return len - towrite;
23711da177e4SLinus Torvalds }
23721da177e4SLinus Torvalds 
23731da177e4SLinus Torvalds #endif
23741da177e4SLinus Torvalds 
2375152a0836SAl Viro static struct dentry *get_super_block(struct file_system_type *fs_type,
2376bd4c625cSLinus Torvalds 			   int flags, const char *dev_name,
2377152a0836SAl Viro 			   void *data)
23781da177e4SLinus Torvalds {
2379152a0836SAl Viro 	return mount_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super);
23801da177e4SLinus Torvalds }
23811da177e4SLinus Torvalds 
2382bd4c625cSLinus Torvalds static int __init init_reiserfs_fs(void)
23831da177e4SLinus Torvalds {
23841da177e4SLinus Torvalds 	int ret;
23851da177e4SLinus Torvalds 
23861da177e4SLinus Torvalds 	if ((ret = init_inodecache())) {
23871da177e4SLinus Torvalds 		return ret;
23881da177e4SLinus Torvalds 	}
23891da177e4SLinus Torvalds 
23901da177e4SLinus Torvalds 	reiserfs_proc_info_global_init();
23911da177e4SLinus Torvalds 
23921da177e4SLinus Torvalds 	ret = register_filesystem(&reiserfs_fs_type);
23931da177e4SLinus Torvalds 
23941da177e4SLinus Torvalds 	if (ret == 0) {
23951da177e4SLinus Torvalds 		return 0;
23961da177e4SLinus Torvalds 	}
23971da177e4SLinus Torvalds 
23981da177e4SLinus Torvalds 	reiserfs_proc_info_global_done();
23991da177e4SLinus Torvalds 	destroy_inodecache();
24001da177e4SLinus Torvalds 
24011da177e4SLinus Torvalds 	return ret;
24021da177e4SLinus Torvalds }
24031da177e4SLinus Torvalds 
2404bd4c625cSLinus Torvalds static void __exit exit_reiserfs_fs(void)
24051da177e4SLinus Torvalds {
24061da177e4SLinus Torvalds 	reiserfs_proc_info_global_done();
24071da177e4SLinus Torvalds 	unregister_filesystem(&reiserfs_fs_type);
24081da177e4SLinus Torvalds 	destroy_inodecache();
24091da177e4SLinus Torvalds }
24101da177e4SLinus Torvalds 
24111da177e4SLinus Torvalds struct file_system_type reiserfs_fs_type = {
24121da177e4SLinus Torvalds 	.owner = THIS_MODULE,
24131da177e4SLinus Torvalds 	.name = "reiserfs",
2414152a0836SAl Viro 	.mount = get_super_block,
2415edc666e2SDavid Howells 	.kill_sb = reiserfs_kill_sb,
24161da177e4SLinus Torvalds 	.fs_flags = FS_REQUIRES_DEV,
24171da177e4SLinus Torvalds };
24181da177e4SLinus Torvalds 
24191da177e4SLinus Torvalds MODULE_DESCRIPTION("ReiserFS journaled filesystem");
24201da177e4SLinus Torvalds MODULE_AUTHOR("Hans Reiser <reiser@namesys.com>");
24211da177e4SLinus Torvalds MODULE_LICENSE("GPL");
24221da177e4SLinus Torvalds 
24231da177e4SLinus Torvalds module_init(init_reiserfs_fs);
24241da177e4SLinus Torvalds module_exit(exit_reiserfs_fs);
2425