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