11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) International Business Machines Corp., 2000-2004
41da177e4SLinus Torvalds * Portions Copyright (C) Christoph Hellwig, 2001-2002
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds #include <linux/fs.h>
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/parser.h>
101da177e4SLinus Torvalds #include <linux/completion.h>
111da177e4SLinus Torvalds #include <linux/vfs.h>
1274abb989SJan Kara #include <linux/quotaops.h>
138fc2751bSMark Bellon #include <linux/mount.h>
141da177e4SLinus Torvalds #include <linux/moduleparam.h>
1591dbb4deSChristoph Hellwig #include <linux/kthread.h>
169a59f452SChristoph Hellwig #include <linux/posix_acl.h>
17115ff50bSDave Kleikamp #include <linux/buffer_head.h>
18a5694255SChristoph Hellwig #include <linux/exportfs.h>
19b5c816a4SColy Li #include <linux/crc32.h>
205a0e3ad6STejun Heo #include <linux/slab.h>
217c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
228fc2751bSMark Bellon #include <linux/seq_file.h>
23b40c2e66STino Reichardt #include <linux/blkdev.h>
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds #include "jfs_incore.h"
261da177e4SLinus Torvalds #include "jfs_filsys.h"
271868f4aaSDave Kleikamp #include "jfs_inode.h"
281da177e4SLinus Torvalds #include "jfs_metapage.h"
291da177e4SLinus Torvalds #include "jfs_superblock.h"
301da177e4SLinus Torvalds #include "jfs_dmap.h"
311da177e4SLinus Torvalds #include "jfs_imap.h"
321da177e4SLinus Torvalds #include "jfs_acl.h"
331da177e4SLinus Torvalds #include "jfs_debug.h"
342cc6a5a0SChristoph Hellwig #include "jfs_xattr.h"
3512fd086dSJan Kara #include "jfs_dinode.h"
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journaled Filesystem (JFS)");
381da177e4SLinus Torvalds MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM");
391da177e4SLinus Torvalds MODULE_LICENSE("GPL");
401da177e4SLinus Torvalds
41e18b890bSChristoph Lameter static struct kmem_cache *jfs_inode_cachep;
421da177e4SLinus Torvalds
43ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jfs_super_operations;
4439655164SChristoph Hellwig static const struct export_operations jfs_export_operations;
451da177e4SLinus Torvalds static struct file_system_type jfs_fs_type;
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds #define MAX_COMMIT_THREADS 64
48789602e9SFabian Frederick static int commit_threads;
491da177e4SLinus Torvalds module_param(commit_threads, int, 0);
501da177e4SLinus Torvalds MODULE_PARM_DESC(commit_threads, "Number of commit threads");
511da177e4SLinus Torvalds
5291dbb4deSChristoph Hellwig static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS];
5391dbb4deSChristoph Hellwig struct task_struct *jfsIOthread;
5491dbb4deSChristoph Hellwig struct task_struct *jfsSyncThread;
551da177e4SLinus Torvalds
561da177e4SLinus Torvalds #ifdef CONFIG_JFS_DEBUG
571da177e4SLinus Torvalds int jfsloglevel = JFS_LOGLEVEL_WARN;
581da177e4SLinus Torvalds module_param(jfsloglevel, int, 0644);
591da177e4SLinus Torvalds MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)");
601da177e4SLinus Torvalds #endif
611da177e4SLinus Torvalds
jfs_handle_error(struct super_block * sb)621da177e4SLinus Torvalds static void jfs_handle_error(struct super_block *sb)
631da177e4SLinus Torvalds {
641da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(sb);
651da177e4SLinus Torvalds
66bc98a42cSDavid Howells if (sb_rdonly(sb))
671da177e4SLinus Torvalds return;
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds updateSuper(sb, FM_DIRTY);
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds if (sbi->flag & JFS_ERR_PANIC)
721da177e4SLinus Torvalds panic("JFS (device %s): panic forced after error\n",
731da177e4SLinus Torvalds sb->s_id);
741da177e4SLinus Torvalds else if (sbi->flag & JFS_ERR_REMOUNT_RO) {
75b18db6deSJoe Perches jfs_err("ERROR: (device %s): remounting filesystem as read-only",
761da177e4SLinus Torvalds sb->s_id);
771751e8a6SLinus Torvalds sb->s_flags |= SB_RDONLY;
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds /* nothing is done for continue beyond marking the superblock dirty */
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds
jfs_error(struct super_block * sb,const char * fmt,...)83eb8630d7SJoe Perches void jfs_error(struct super_block *sb, const char *fmt, ...)
841da177e4SLinus Torvalds {
85eb8630d7SJoe Perches struct va_format vaf;
861da177e4SLinus Torvalds va_list args;
871da177e4SLinus Torvalds
88eb8630d7SJoe Perches va_start(args, fmt);
891da177e4SLinus Torvalds
90eb8630d7SJoe Perches vaf.fmt = fmt;
91eb8630d7SJoe Perches vaf.va = &args;
92eb8630d7SJoe Perches
937d2ac456SScott Wood pr_err("ERROR: (device %s): %ps: %pV\n",
94eb8630d7SJoe Perches sb->s_id, __builtin_return_address(0), &vaf);
95eb8630d7SJoe Perches
96eb8630d7SJoe Perches va_end(args);
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds jfs_handle_error(sb);
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds
jfs_alloc_inode(struct super_block * sb)1011da177e4SLinus Torvalds static struct inode *jfs_alloc_inode(struct super_block *sb)
1021da177e4SLinus Torvalds {
1031da177e4SLinus Torvalds struct jfs_inode_info *jfs_inode;
1041da177e4SLinus Torvalds
105fd60b288SMuchun Song jfs_inode = alloc_inode_sb(sb, jfs_inode_cachep, GFP_NOFS);
1061da177e4SLinus Torvalds if (!jfs_inode)
1071da177e4SLinus Torvalds return NULL;
108507e1fa6SJan Kara #ifdef CONFIG_QUOTA
109507e1fa6SJan Kara memset(&jfs_inode->i_dquot, 0, sizeof(jfs_inode->i_dquot));
110507e1fa6SJan Kara #endif
1111da177e4SLinus Torvalds return &jfs_inode->vfs_inode;
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds
jfs_free_inode(struct inode * inode)114b3b4a6e3SAl Viro static void jfs_free_inode(struct inode *inode)
115fa0d7e3dSNick Piggin {
116b3b4a6e3SAl Viro kmem_cache_free(jfs_inode_cachep, JFS_IP(inode));
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds
jfs_statfs(struct dentry * dentry,struct kstatfs * buf)119726c3342SDavid Howells static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1201da177e4SLinus Torvalds {
121726c3342SDavid Howells struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb);
1221da177e4SLinus Torvalds s64 maxinodes;
1231da177e4SLinus Torvalds struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap;
1241da177e4SLinus Torvalds
1251da177e4SLinus Torvalds jfs_info("In jfs_statfs");
1261da177e4SLinus Torvalds buf->f_type = JFS_SUPER_MAGIC;
1271da177e4SLinus Torvalds buf->f_bsize = sbi->bsize;
1281da177e4SLinus Torvalds buf->f_blocks = sbi->bmap->db_mapsize;
1291da177e4SLinus Torvalds buf->f_bfree = sbi->bmap->db_nfree;
1301da177e4SLinus Torvalds buf->f_bavail = sbi->bmap->db_nfree;
1311da177e4SLinus Torvalds /*
1321da177e4SLinus Torvalds * If we really return the number of allocated & free inodes, some
1331da177e4SLinus Torvalds * applications will fail because they won't see enough free inodes.
1344de80273SPhilippe De Muyter * We'll try to calculate some guess as to how many inodes we can
1351da177e4SLinus Torvalds * really allocate
1361da177e4SLinus Torvalds *
1371da177e4SLinus Torvalds * buf->f_files = atomic_read(&imap->im_numinos);
1381da177e4SLinus Torvalds * buf->f_ffree = atomic_read(&imap->im_numfree);
1391da177e4SLinus Torvalds */
1401da177e4SLinus Torvalds maxinodes = min((s64) atomic_read(&imap->im_numinos) +
1411da177e4SLinus Torvalds ((sbi->bmap->db_nfree >> imap->im_l2nbperiext)
1421da177e4SLinus Torvalds << L2INOSPEREXT), (s64) 0xffffffffLL);
1431da177e4SLinus Torvalds buf->f_files = maxinodes;
1441da177e4SLinus Torvalds buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) -
1451da177e4SLinus Torvalds atomic_read(&imap->im_numfree));
1462e3bc612SAndy Shevchenko buf->f_fsid.val[0] = crc32_le(0, (char *)&sbi->uuid,
1472e3bc612SAndy Shevchenko sizeof(sbi->uuid)/2);
1482e3bc612SAndy Shevchenko buf->f_fsid.val[1] = crc32_le(0,
1492e3bc612SAndy Shevchenko (char *)&sbi->uuid + sizeof(sbi->uuid)/2,
150b5c816a4SColy Li sizeof(sbi->uuid)/2);
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds buf->f_namelen = JFS_NAME_MAX;
1531da177e4SLinus Torvalds return 0;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds
15612fd086dSJan Kara #ifdef CONFIG_QUOTA
15712fd086dSJan Kara static int jfs_quota_off(struct super_block *sb, int type);
15812fd086dSJan Kara static int jfs_quota_on(struct super_block *sb, int type, int format_id,
15912fd086dSJan Kara const struct path *path);
16012fd086dSJan Kara
jfs_quota_off_umount(struct super_block * sb)16112fd086dSJan Kara static void jfs_quota_off_umount(struct super_block *sb)
16212fd086dSJan Kara {
16312fd086dSJan Kara int type;
16412fd086dSJan Kara
16512fd086dSJan Kara for (type = 0; type < MAXQUOTAS; type++)
16612fd086dSJan Kara jfs_quota_off(sb, type);
16712fd086dSJan Kara }
16812fd086dSJan Kara
16912fd086dSJan Kara static const struct quotactl_ops jfs_quotactl_ops = {
17012fd086dSJan Kara .quota_on = jfs_quota_on,
17112fd086dSJan Kara .quota_off = jfs_quota_off,
17212fd086dSJan Kara .quota_sync = dquot_quota_sync,
17312fd086dSJan Kara .get_state = dquot_get_state,
17412fd086dSJan Kara .set_info = dquot_set_dqinfo,
17512fd086dSJan Kara .get_dqblk = dquot_get_dqblk,
17612fd086dSJan Kara .set_dqblk = dquot_set_dqblk,
17712fd086dSJan Kara .get_nextdqblk = dquot_get_next_dqblk,
17812fd086dSJan Kara };
17912fd086dSJan Kara #else
jfs_quota_off_umount(struct super_block * sb)18012fd086dSJan Kara static inline void jfs_quota_off_umount(struct super_block *sb)
18112fd086dSJan Kara {
18212fd086dSJan Kara }
18312fd086dSJan Kara #endif
18412fd086dSJan Kara
jfs_put_super(struct super_block * sb)1851da177e4SLinus Torvalds static void jfs_put_super(struct super_block *sb)
1861da177e4SLinus Torvalds {
1871da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(sb);
1881da177e4SLinus Torvalds int rc;
1891da177e4SLinus Torvalds
1901da177e4SLinus Torvalds jfs_info("In jfs_put_super");
1916cfd0148SChristoph Hellwig
19212fd086dSJan Kara jfs_quota_off_umount(sb);
193e0ccfd95SChristoph Hellwig
1941da177e4SLinus Torvalds rc = jfs_umount(sb);
1951da177e4SLinus Torvalds if (rc)
1961da177e4SLinus Torvalds jfs_err("jfs_umount failed with return code %d", rc);
1976d729e44SThomas Gleixner
1981da177e4SLinus Torvalds unload_nls(sbi->nls_tab);
1991da177e4SLinus Torvalds
2007fab479bSDave Kleikamp truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
2017fab479bSDave Kleikamp iput(sbi->direct_inode);
2027fab479bSDave Kleikamp
2031da177e4SLinus Torvalds kfree(sbi);
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds
2061da177e4SLinus Torvalds enum {
2071da177e4SLinus Torvalds Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
2088fc2751bSMark Bellon Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota,
209b40c2e66STino Reichardt Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask,
210b40c2e66STino Reichardt Opt_discard, Opt_nodiscard, Opt_discard_minblk
2111da177e4SLinus Torvalds };
2121da177e4SLinus Torvalds
213a447c093SSteven Whitehouse static const match_table_t tokens = {
2141da177e4SLinus Torvalds {Opt_integrity, "integrity"},
2151da177e4SLinus Torvalds {Opt_nointegrity, "nointegrity"},
2161da177e4SLinus Torvalds {Opt_iocharset, "iocharset=%s"},
2171da177e4SLinus Torvalds {Opt_resize, "resize=%u"},
2181da177e4SLinus Torvalds {Opt_resize_nosize, "resize"},
2191da177e4SLinus Torvalds {Opt_errors, "errors=%s"},
2201da177e4SLinus Torvalds {Opt_ignore, "noquota"},
22102645bcdSChengguang Xu {Opt_quota, "quota"},
2228fc2751bSMark Bellon {Opt_usrquota, "usrquota"},
2238fc2751bSMark Bellon {Opt_grpquota, "grpquota"},
22469eb66d7SDave Kleikamp {Opt_uid, "uid=%u"},
22569eb66d7SDave Kleikamp {Opt_gid, "gid=%u"},
22669eb66d7SDave Kleikamp {Opt_umask, "umask=%u"},
227b40c2e66STino Reichardt {Opt_discard, "discard"},
228b40c2e66STino Reichardt {Opt_nodiscard, "nodiscard"},
229b40c2e66STino Reichardt {Opt_discard_minblk, "discard=%u"},
2301da177e4SLinus Torvalds {Opt_err, NULL}
2311da177e4SLinus Torvalds };
2321da177e4SLinus Torvalds
parse_options(char * options,struct super_block * sb,s64 * newLVSize,int * flag)2331da177e4SLinus Torvalds static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
2341da177e4SLinus Torvalds int *flag)
2351da177e4SLinus Torvalds {
2361da177e4SLinus Torvalds void *nls_map = (void *)-1; /* -1: no change; NULL: none */
2371da177e4SLinus Torvalds char *p;
2381da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(sb);
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds *newLVSize = 0;
2411da177e4SLinus Torvalds
2421da177e4SLinus Torvalds if (!options)
2431da177e4SLinus Torvalds return 1;
2441da177e4SLinus Torvalds
2451da177e4SLinus Torvalds while ((p = strsep(&options, ",")) != NULL) {
2461da177e4SLinus Torvalds substring_t args[MAX_OPT_ARGS];
2471da177e4SLinus Torvalds int token;
2481da177e4SLinus Torvalds if (!*p)
2491da177e4SLinus Torvalds continue;
2501da177e4SLinus Torvalds
2511da177e4SLinus Torvalds token = match_token(p, tokens, args);
2521da177e4SLinus Torvalds switch (token) {
2531da177e4SLinus Torvalds case Opt_integrity:
2541da177e4SLinus Torvalds *flag &= ~JFS_NOINTEGRITY;
2551da177e4SLinus Torvalds break;
2561da177e4SLinus Torvalds case Opt_nointegrity:
2571da177e4SLinus Torvalds *flag |= JFS_NOINTEGRITY;
2581da177e4SLinus Torvalds break;
2591da177e4SLinus Torvalds case Opt_ignore:
2601da177e4SLinus Torvalds /* Silently ignore the quota options */
2611da177e4SLinus Torvalds /* Don't do anything ;-) */
2621da177e4SLinus Torvalds break;
2631da177e4SLinus Torvalds case Opt_iocharset:
2641da177e4SLinus Torvalds if (nls_map && nls_map != (void *) -1)
2651da177e4SLinus Torvalds unload_nls(nls_map);
2661da177e4SLinus Torvalds if (!strcmp(args[0].from, "none"))
2671da177e4SLinus Torvalds nls_map = NULL;
2681da177e4SLinus Torvalds else {
2691da177e4SLinus Torvalds nls_map = load_nls(args[0].from);
2701da177e4SLinus Torvalds if (!nls_map) {
271b40c2e66STino Reichardt pr_err("JFS: charset not found\n");
2721da177e4SLinus Torvalds goto cleanup;
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds break;
2761da177e4SLinus Torvalds case Opt_resize:
2771da177e4SLinus Torvalds {
2781da177e4SLinus Torvalds char *resize = args[0].from;
279bb5e50aaSFabian Frederick int rc = kstrtoll(resize, 0, newLVSize);
280bb5e50aaSFabian Frederick
281bb5e50aaSFabian Frederick if (rc)
282bb5e50aaSFabian Frederick goto cleanup;
2831da177e4SLinus Torvalds break;
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds case Opt_resize_nosize:
2861da177e4SLinus Torvalds {
287dd0c0bdfSChristoph Hellwig *newLVSize = sb_bdev_nr_blocks(sb);
2881da177e4SLinus Torvalds if (*newLVSize == 0)
289b40c2e66STino Reichardt pr_err("JFS: Cannot determine volume size\n");
2901da177e4SLinus Torvalds break;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds case Opt_errors:
2931da177e4SLinus Torvalds {
2941da177e4SLinus Torvalds char *errors = args[0].from;
2951da177e4SLinus Torvalds if (!errors || !*errors)
2961da177e4SLinus Torvalds goto cleanup;
2971da177e4SLinus Torvalds if (!strcmp(errors, "continue")) {
2981da177e4SLinus Torvalds *flag &= ~JFS_ERR_REMOUNT_RO;
2991da177e4SLinus Torvalds *flag &= ~JFS_ERR_PANIC;
3001da177e4SLinus Torvalds *flag |= JFS_ERR_CONTINUE;
3011da177e4SLinus Torvalds } else if (!strcmp(errors, "remount-ro")) {
3021da177e4SLinus Torvalds *flag &= ~JFS_ERR_CONTINUE;
3031da177e4SLinus Torvalds *flag &= ~JFS_ERR_PANIC;
3041da177e4SLinus Torvalds *flag |= JFS_ERR_REMOUNT_RO;
3051da177e4SLinus Torvalds } else if (!strcmp(errors, "panic")) {
3061da177e4SLinus Torvalds *flag &= ~JFS_ERR_CONTINUE;
3071da177e4SLinus Torvalds *flag &= ~JFS_ERR_REMOUNT_RO;
3081da177e4SLinus Torvalds *flag |= JFS_ERR_PANIC;
3091da177e4SLinus Torvalds } else {
310b40c2e66STino Reichardt pr_err("JFS: %s is an invalid error handler\n",
3111da177e4SLinus Torvalds errors);
3121da177e4SLinus Torvalds goto cleanup;
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds break;
3151da177e4SLinus Torvalds }
3168fc2751bSMark Bellon
317115ff50bSDave Kleikamp #ifdef CONFIG_QUOTA
3188fc2751bSMark Bellon case Opt_quota:
3198fc2751bSMark Bellon case Opt_usrquota:
3208fc2751bSMark Bellon *flag |= JFS_USRQUOTA;
3218fc2751bSMark Bellon break;
3228fc2751bSMark Bellon case Opt_grpquota:
3238fc2751bSMark Bellon *flag |= JFS_GRPQUOTA;
3248fc2751bSMark Bellon break;
3258fc2751bSMark Bellon #else
3268fc2751bSMark Bellon case Opt_usrquota:
3278fc2751bSMark Bellon case Opt_grpquota:
3288fc2751bSMark Bellon case Opt_quota:
329b40c2e66STino Reichardt pr_err("JFS: quota operations not supported\n");
3308fc2751bSMark Bellon break;
3318fc2751bSMark Bellon #endif
33269eb66d7SDave Kleikamp case Opt_uid:
33369eb66d7SDave Kleikamp {
33469eb66d7SDave Kleikamp char *uid = args[0].from;
335bb5e50aaSFabian Frederick uid_t val;
336bb5e50aaSFabian Frederick int rc = kstrtouint(uid, 0, &val);
337bb5e50aaSFabian Frederick
338bb5e50aaSFabian Frederick if (rc)
339bb5e50aaSFabian Frederick goto cleanup;
340c18cdc1aSEric W. Biederman sbi->uid = make_kuid(current_user_ns(), val);
341c18cdc1aSEric W. Biederman if (!uid_valid(sbi->uid))
342c18cdc1aSEric W. Biederman goto cleanup;
34369eb66d7SDave Kleikamp break;
34469eb66d7SDave Kleikamp }
345b40c2e66STino Reichardt
34669eb66d7SDave Kleikamp case Opt_gid:
34769eb66d7SDave Kleikamp {
34869eb66d7SDave Kleikamp char *gid = args[0].from;
349bb5e50aaSFabian Frederick gid_t val;
350bb5e50aaSFabian Frederick int rc = kstrtouint(gid, 0, &val);
351bb5e50aaSFabian Frederick
352bb5e50aaSFabian Frederick if (rc)
353bb5e50aaSFabian Frederick goto cleanup;
354c18cdc1aSEric W. Biederman sbi->gid = make_kgid(current_user_ns(), val);
355c18cdc1aSEric W. Biederman if (!gid_valid(sbi->gid))
356c18cdc1aSEric W. Biederman goto cleanup;
35769eb66d7SDave Kleikamp break;
35869eb66d7SDave Kleikamp }
359b40c2e66STino Reichardt
36069eb66d7SDave Kleikamp case Opt_umask:
36169eb66d7SDave Kleikamp {
36269eb66d7SDave Kleikamp char *umask = args[0].from;
363bb5e50aaSFabian Frederick int rc = kstrtouint(umask, 8, &sbi->umask);
364bb5e50aaSFabian Frederick
365bb5e50aaSFabian Frederick if (rc)
366bb5e50aaSFabian Frederick goto cleanup;
36769eb66d7SDave Kleikamp if (sbi->umask & ~0777) {
368b40c2e66STino Reichardt pr_err("JFS: Invalid value of umask\n");
36969eb66d7SDave Kleikamp goto cleanup;
37069eb66d7SDave Kleikamp }
37169eb66d7SDave Kleikamp break;
37269eb66d7SDave Kleikamp }
373b40c2e66STino Reichardt
374b40c2e66STino Reichardt case Opt_discard:
375b40c2e66STino Reichardt /* if set to 1, even copying files will cause
376b40c2e66STino Reichardt * trimming :O
377b40c2e66STino Reichardt * -> user has more control over the online trimming
378b40c2e66STino Reichardt */
379b40c2e66STino Reichardt sbi->minblks_trim = 64;
38070200574SChristoph Hellwig if (bdev_max_discard_sectors(sb->s_bdev))
381b40c2e66STino Reichardt *flag |= JFS_DISCARD;
382789602e9SFabian Frederick else
383789602e9SFabian Frederick pr_err("JFS: discard option not supported on device\n");
384b40c2e66STino Reichardt break;
385b40c2e66STino Reichardt
386b40c2e66STino Reichardt case Opt_nodiscard:
387b40c2e66STino Reichardt *flag &= ~JFS_DISCARD;
388b40c2e66STino Reichardt break;
389b40c2e66STino Reichardt
390b40c2e66STino Reichardt case Opt_discard_minblk:
391b40c2e66STino Reichardt {
392b40c2e66STino Reichardt char *minblks_trim = args[0].from;
393bb5e50aaSFabian Frederick int rc;
39470200574SChristoph Hellwig if (bdev_max_discard_sectors(sb->s_bdev)) {
395b40c2e66STino Reichardt *flag |= JFS_DISCARD;
396bb5e50aaSFabian Frederick rc = kstrtouint(minblks_trim, 0,
397bb5e50aaSFabian Frederick &sbi->minblks_trim);
398bb5e50aaSFabian Frederick if (rc)
399bb5e50aaSFabian Frederick goto cleanup;
400bb5e50aaSFabian Frederick } else
401789602e9SFabian Frederick pr_err("JFS: discard option not supported on device\n");
402b40c2e66STino Reichardt break;
403b40c2e66STino Reichardt }
404b40c2e66STino Reichardt
4051da177e4SLinus Torvalds default:
406789602e9SFabian Frederick printk("jfs: Unrecognized mount option \"%s\" or missing value\n",
407789602e9SFabian Frederick p);
4081da177e4SLinus Torvalds goto cleanup;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds
4121da177e4SLinus Torvalds if (nls_map != (void *) -1) {
4131da177e4SLinus Torvalds /* Discard old (if remount) */
4141da177e4SLinus Torvalds unload_nls(sbi->nls_tab);
4151da177e4SLinus Torvalds sbi->nls_tab = nls_map;
4161da177e4SLinus Torvalds }
4171da177e4SLinus Torvalds return 1;
4181da177e4SLinus Torvalds
4191da177e4SLinus Torvalds cleanup:
4201da177e4SLinus Torvalds if (nls_map && nls_map != (void *) -1)
4211da177e4SLinus Torvalds unload_nls(nls_map);
4221da177e4SLinus Torvalds return 0;
4231da177e4SLinus Torvalds }
4241da177e4SLinus Torvalds
jfs_remount(struct super_block * sb,int * flags,char * data)4251da177e4SLinus Torvalds static int jfs_remount(struct super_block *sb, int *flags, char *data)
4261da177e4SLinus Torvalds {
4271da177e4SLinus Torvalds s64 newLVSize = 0;
4281da177e4SLinus Torvalds int rc = 0;
4291da177e4SLinus Torvalds int flag = JFS_SBI(sb)->flag;
430337eb00aSAlessio Igor Bogani int ret;
4311da177e4SLinus Torvalds
43202b9984dSTheodore Ts'o sync_filesystem(sb);
433789602e9SFabian Frederick if (!parse_options(data, sb, &newLVSize, &flag))
4341da177e4SLinus Torvalds return -EINVAL;
43522b26db6SJan Blunck
4361da177e4SLinus Torvalds if (newLVSize) {
437bc98a42cSDavid Howells if (sb_rdonly(sb)) {
438789602e9SFabian Frederick pr_err("JFS: resize requires volume to be mounted read-write\n");
4391da177e4SLinus Torvalds return -EROFS;
4401da177e4SLinus Torvalds }
4411da177e4SLinus Torvalds rc = jfs_extendfs(sb, newLVSize, 0);
44222b26db6SJan Blunck if (rc)
4431da177e4SLinus Torvalds return rc;
4441da177e4SLinus Torvalds }
4451da177e4SLinus Torvalds
4461751e8a6SLinus Torvalds if (sb_rdonly(sb) && !(*flags & SB_RDONLY)) {
4477fab479bSDave Kleikamp /*
4487fab479bSDave Kleikamp * Invalidate any previously read metadata. fsck may have
4497fab479bSDave Kleikamp * changed the on-disk data since we mounted r/o
4507fab479bSDave Kleikamp */
4517fab479bSDave Kleikamp truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0);
4527fab479bSDave Kleikamp
4531da177e4SLinus Torvalds JFS_SBI(sb)->flag = flag;
454337eb00aSAlessio Igor Bogani ret = jfs_mount_rw(sb, 1);
455c79d967dSChristoph Hellwig
456c79d967dSChristoph Hellwig /* mark the fs r/w for quota activity */
4571751e8a6SLinus Torvalds sb->s_flags &= ~SB_RDONLY;
458c79d967dSChristoph Hellwig
4590f0dd62fSChristoph Hellwig dquot_resume(sb, -1);
460337eb00aSAlessio Igor Bogani return ret;
4611da177e4SLinus Torvalds }
4621751e8a6SLinus Torvalds if (!sb_rdonly(sb) && (*flags & SB_RDONLY)) {
4630f0dd62fSChristoph Hellwig rc = dquot_suspend(sb, -1);
464789602e9SFabian Frederick if (rc < 0)
4650f0dd62fSChristoph Hellwig return rc;
4661da177e4SLinus Torvalds rc = jfs_umount_rw(sb);
4671da177e4SLinus Torvalds JFS_SBI(sb)->flag = flag;
4681da177e4SLinus Torvalds return rc;
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY))
471bc98a42cSDavid Howells if (!sb_rdonly(sb)) {
4721da177e4SLinus Torvalds rc = jfs_umount_rw(sb);
47322b26db6SJan Blunck if (rc)
4741da177e4SLinus Torvalds return rc;
47522b26db6SJan Blunck
4761da177e4SLinus Torvalds JFS_SBI(sb)->flag = flag;
477337eb00aSAlessio Igor Bogani ret = jfs_mount_rw(sb, 1);
478337eb00aSAlessio Igor Bogani return ret;
4791da177e4SLinus Torvalds }
4801da177e4SLinus Torvalds JFS_SBI(sb)->flag = flag;
4811da177e4SLinus Torvalds
4821da177e4SLinus Torvalds return 0;
4831da177e4SLinus Torvalds }
4841da177e4SLinus Torvalds
jfs_fill_super(struct super_block * sb,void * data,int silent)4851da177e4SLinus Torvalds static int jfs_fill_super(struct super_block *sb, void *data, int silent)
4861da177e4SLinus Torvalds {
4871da177e4SLinus Torvalds struct jfs_sb_info *sbi;
4881da177e4SLinus Torvalds struct inode *inode;
4891da177e4SLinus Torvalds int rc;
4901da177e4SLinus Torvalds s64 newLVSize = 0;
491eab1df71SDavid Howells int flag, ret = -EINVAL;
4921da177e4SLinus Torvalds
4931da177e4SLinus Torvalds jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags);
4941da177e4SLinus Torvalds
4955b3030e3SEric Sesterhenn sbi = kzalloc(sizeof(struct jfs_sb_info), GFP_KERNEL);
49622b26db6SJan Blunck if (!sbi)
497087387f9SAkinobu Mita return -ENOMEM;
49822b26db6SJan Blunck
4991da177e4SLinus Torvalds sb->s_fs_info = sbi;
5008de52778SAl Viro sb->s_max_links = JFS_LINK_MAX;
50122b13969SDeepa Dinamani sb->s_time_min = 0;
50222b13969SDeepa Dinamani sb->s_time_max = U32_MAX;
5031da177e4SLinus Torvalds sbi->sb = sb;
504c18cdc1aSEric W. Biederman sbi->uid = INVALID_UID;
505c18cdc1aSEric W. Biederman sbi->gid = INVALID_GID;
506c18cdc1aSEric W. Biederman sbi->umask = -1;
5071da177e4SLinus Torvalds
5081da177e4SLinus Torvalds /* initialize the mount flag and determine the default error handler */
5091da177e4SLinus Torvalds flag = JFS_ERR_REMOUNT_RO;
5101da177e4SLinus Torvalds
511684bdc7fSJan Blunck if (!parse_options((char *) data, sb, &newLVSize, &flag))
512684bdc7fSJan Blunck goto out_kfree;
5131da177e4SLinus Torvalds sbi->flag = flag;
5141da177e4SLinus Torvalds
5151da177e4SLinus Torvalds #ifdef CONFIG_JFS_POSIX_ACL
5161751e8a6SLinus Torvalds sb->s_flags |= SB_POSIXACL;
5171da177e4SLinus Torvalds #endif
5181da177e4SLinus Torvalds
5191da177e4SLinus Torvalds if (newLVSize) {
520b40c2e66STino Reichardt pr_err("resize option for remount only\n");
521684bdc7fSJan Blunck goto out_kfree;
5221da177e4SLinus Torvalds }
5231da177e4SLinus Torvalds
5241da177e4SLinus Torvalds /*
5251da177e4SLinus Torvalds * Initialize blocksize to 4K.
5261da177e4SLinus Torvalds */
5271da177e4SLinus Torvalds sb_set_blocksize(sb, PSIZE);
5281da177e4SLinus Torvalds
5291da177e4SLinus Torvalds /*
5301da177e4SLinus Torvalds * Set method vectors.
5311da177e4SLinus Torvalds */
5321da177e4SLinus Torvalds sb->s_op = &jfs_super_operations;
5331da177e4SLinus Torvalds sb->s_export_op = &jfs_export_operations;
5342cc6a5a0SChristoph Hellwig sb->s_xattr = jfs_xattr_handlers;
535123e9cafSChristoph Hellwig #ifdef CONFIG_QUOTA
536123e9cafSChristoph Hellwig sb->dq_op = &dquot_operations;
53712fd086dSJan Kara sb->s_qcop = &jfs_quotactl_ops;
538507e1fa6SJan Kara sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
539123e9cafSChristoph Hellwig #endif
5401da177e4SLinus Torvalds
5417fab479bSDave Kleikamp /*
5427fab479bSDave Kleikamp * Initialize direct-mapping inode/address-space
5437fab479bSDave Kleikamp */
5447fab479bSDave Kleikamp inode = new_inode(sb);
545eab1df71SDavid Howells if (inode == NULL) {
546eab1df71SDavid Howells ret = -ENOMEM;
547684bdc7fSJan Blunck goto out_unload;
548eab1df71SDavid Howells }
54974e157e6SChristoph Hellwig inode->i_size = bdev_nr_bytes(sb->s_bdev);
5507fab479bSDave Kleikamp inode->i_mapping->a_ops = &jfs_metapage_aops;
5515bef9151SAl Viro inode_fake_hash(inode);
5527fab479bSDave Kleikamp mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
5537fab479bSDave Kleikamp
5547fab479bSDave Kleikamp sbi->direct_inode = inode;
5557fab479bSDave Kleikamp
5561da177e4SLinus Torvalds rc = jfs_mount(sb);
5571da177e4SLinus Torvalds if (rc) {
558789602e9SFabian Frederick if (!silent)
5591da177e4SLinus Torvalds jfs_err("jfs_mount failed w/return code = %d", rc);
5607fab479bSDave Kleikamp goto out_mount_failed;
5611da177e4SLinus Torvalds }
562bc98a42cSDavid Howells if (sb_rdonly(sb))
5631da177e4SLinus Torvalds sbi->log = NULL;
5641da177e4SLinus Torvalds else {
5651da177e4SLinus Torvalds rc = jfs_mount_rw(sb, 0);
5661da177e4SLinus Torvalds if (rc) {
5671da177e4SLinus Torvalds if (!silent) {
5681da177e4SLinus Torvalds jfs_err("jfs_mount_rw failed, return code = %d",
5691da177e4SLinus Torvalds rc);
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds goto out_no_rw;
5721da177e4SLinus Torvalds }
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds
5751da177e4SLinus Torvalds sb->s_magic = JFS_SUPER_MAGIC;
5761da177e4SLinus Torvalds
57794b77bd8SAl Viro if (sbi->mntflag & JFS_OS2)
57894b77bd8SAl Viro sb->s_d_op = &jfs_ci_dentry_operations;
57994b77bd8SAl Viro
580eab1df71SDavid Howells inode = jfs_iget(sb, ROOT_I);
581eab1df71SDavid Howells if (IS_ERR(inode)) {
582eab1df71SDavid Howells ret = PTR_ERR(inode);
5836536d289SDave Kleikamp goto out_no_rw;
584eab1df71SDavid Howells }
58548fde701SAl Viro sb->s_root = d_make_root(inode);
5861da177e4SLinus Torvalds if (!sb->s_root)
5871da177e4SLinus Torvalds goto out_no_root;
5881da177e4SLinus Torvalds
589c227390cSDave Kleikamp /* logical blocks are represented by 40 bits in pxd_t, etc.
590c227390cSDave Kleikamp * and page cache is indexed by long
5911da177e4SLinus Torvalds */
592c227390cSDave Kleikamp sb->s_maxbytes = min(((loff_t)sb->s_blocksize) << 40, MAX_LFS_FILESIZE);
5931da177e4SLinus Torvalds sb->s_time_gran = 1;
5941da177e4SLinus Torvalds return 0;
5951da177e4SLinus Torvalds
5961da177e4SLinus Torvalds out_no_root:
5976536d289SDave Kleikamp jfs_err("jfs_read_super: get root dentry failed");
5981da177e4SLinus Torvalds
5991da177e4SLinus Torvalds out_no_rw:
6001da177e4SLinus Torvalds rc = jfs_umount(sb);
601789602e9SFabian Frederick if (rc)
6021da177e4SLinus Torvalds jfs_err("jfs_umount failed with return code %d", rc);
6037fab479bSDave Kleikamp out_mount_failed:
60428fd1298SOGAWA Hirofumi filemap_write_and_wait(sbi->direct_inode->i_mapping);
6057fab479bSDave Kleikamp truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
6067fab479bSDave Kleikamp make_bad_inode(sbi->direct_inode);
6077fab479bSDave Kleikamp iput(sbi->direct_inode);
6087fab479bSDave Kleikamp sbi->direct_inode = NULL;
609684bdc7fSJan Blunck out_unload:
6101da177e4SLinus Torvalds unload_nls(sbi->nls_tab);
611684bdc7fSJan Blunck out_kfree:
6121da177e4SLinus Torvalds kfree(sbi);
613eab1df71SDavid Howells return ret;
6141da177e4SLinus Torvalds }
6151da177e4SLinus Torvalds
jfs_freeze(struct super_block * sb)616c4be0c1dSTakashi Sato static int jfs_freeze(struct super_block *sb)
6171da177e4SLinus Torvalds {
6181da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(sb);
6191da177e4SLinus Torvalds struct jfs_log *log = sbi->log;
620e9b37667SVahram Martirosyan int rc = 0;
6211da177e4SLinus Torvalds
622bc98a42cSDavid Howells if (!sb_rdonly(sb)) {
6231da177e4SLinus Torvalds txQuiesce(sb);
624e9b37667SVahram Martirosyan rc = lmLogShutdown(log);
625e9b37667SVahram Martirosyan if (rc) {
626eb8630d7SJoe Perches jfs_error(sb, "lmLogShutdown failed\n");
627e9b37667SVahram Martirosyan
628e9b37667SVahram Martirosyan /* let operations fail rather than hang */
629e9b37667SVahram Martirosyan txResume(sb);
630e9b37667SVahram Martirosyan
631e9b37667SVahram Martirosyan return rc;
632e9b37667SVahram Martirosyan }
633e9b37667SVahram Martirosyan rc = updateSuper(sb, FM_CLEAN);
634e9b37667SVahram Martirosyan if (rc) {
635b18db6deSJoe Perches jfs_err("jfs_freeze: updateSuper failed");
636e9b37667SVahram Martirosyan /*
637e9b37667SVahram Martirosyan * Don't fail here. Everything succeeded except
638e9b37667SVahram Martirosyan * marking the superblock clean, so there's really
639e9b37667SVahram Martirosyan * no harm in leaving it frozen for now.
640e9b37667SVahram Martirosyan */
641e9b37667SVahram Martirosyan }
6421da177e4SLinus Torvalds }
643c4be0c1dSTakashi Sato return 0;
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds
jfs_unfreeze(struct super_block * sb)646c4be0c1dSTakashi Sato static int jfs_unfreeze(struct super_block *sb)
6471da177e4SLinus Torvalds {
6481da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(sb);
6491da177e4SLinus Torvalds struct jfs_log *log = sbi->log;
6501da177e4SLinus Torvalds int rc = 0;
6511da177e4SLinus Torvalds
652bc98a42cSDavid Howells if (!sb_rdonly(sb)) {
653e9b37667SVahram Martirosyan rc = updateSuper(sb, FM_MOUNT);
654e9b37667SVahram Martirosyan if (rc) {
655eb8630d7SJoe Perches jfs_error(sb, "updateSuper failed\n");
656e9b37667SVahram Martirosyan goto out;
657e9b37667SVahram Martirosyan }
658e9b37667SVahram Martirosyan rc = lmLogInit(log);
659e9b37667SVahram Martirosyan if (rc)
660eb8630d7SJoe Perches jfs_error(sb, "lmLogInit failed\n");
661e9b37667SVahram Martirosyan out:
6621da177e4SLinus Torvalds txResume(sb);
6631da177e4SLinus Torvalds }
664e9b37667SVahram Martirosyan return rc;
6651da177e4SLinus Torvalds }
6661da177e4SLinus Torvalds
jfs_do_mount(struct file_system_type * fs_type,int flags,const char * dev_name,void * data)667152a0836SAl Viro static struct dentry *jfs_do_mount(struct file_system_type *fs_type,
668152a0836SAl Viro int flags, const char *dev_name, void *data)
6691da177e4SLinus Torvalds {
670152a0836SAl Viro return mount_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
6711da177e4SLinus Torvalds }
6721da177e4SLinus Torvalds
jfs_sync_fs(struct super_block * sb,int wait)6731da177e4SLinus Torvalds static int jfs_sync_fs(struct super_block *sb, int wait)
6741da177e4SLinus Torvalds {
6751da177e4SLinus Torvalds struct jfs_log *log = JFS_SBI(sb)->log;
6761da177e4SLinus Torvalds
6771da177e4SLinus Torvalds /* log == NULL indicates read-only mount */
6781c627829SDave Kleikamp if (log) {
679a1177825SJan Kara /*
680a1177825SJan Kara * Write quota structures to quota file, sync_blockdev() will
681a1177825SJan Kara * write them to disk later
682a1177825SJan Kara */
683a1177825SJan Kara dquot_writeback_dquots(sb, -1);
6841da177e4SLinus Torvalds jfs_flush_journal(log, wait);
685cbc3d65eSDave Kleikamp jfs_syncpt(log, 0);
6861c627829SDave Kleikamp }
6871da177e4SLinus Torvalds
6881da177e4SLinus Torvalds return 0;
6891da177e4SLinus Torvalds }
6901da177e4SLinus Torvalds
jfs_show_options(struct seq_file * seq,struct dentry * root)69134c80b1dSAl Viro static int jfs_show_options(struct seq_file *seq, struct dentry *root)
6928fc2751bSMark Bellon {
69334c80b1dSAl Viro struct jfs_sb_info *sbi = JFS_SBI(root->d_sb);
6948fc2751bSMark Bellon
695c18cdc1aSEric W. Biederman if (uid_valid(sbi->uid))
696c18cdc1aSEric W. Biederman seq_printf(seq, ",uid=%d", from_kuid(&init_user_ns, sbi->uid));
697c18cdc1aSEric W. Biederman if (gid_valid(sbi->gid))
698c18cdc1aSEric W. Biederman seq_printf(seq, ",gid=%d", from_kgid(&init_user_ns, sbi->gid));
69969eb66d7SDave Kleikamp if (sbi->umask != -1)
70069eb66d7SDave Kleikamp seq_printf(seq, ",umask=%03o", sbi->umask);
7018fc2751bSMark Bellon if (sbi->flag & JFS_NOINTEGRITY)
7028fc2751bSMark Bellon seq_puts(seq, ",nointegrity");
703b40c2e66STino Reichardt if (sbi->flag & JFS_DISCARD)
704b40c2e66STino Reichardt seq_printf(seq, ",discard=%u", sbi->minblks_trim);
7055c5e32ceSMiklos Szeredi if (sbi->nls_tab)
7065c5e32ceSMiklos Szeredi seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);
7075c5e32ceSMiklos Szeredi if (sbi->flag & JFS_ERR_CONTINUE)
7085c5e32ceSMiklos Szeredi seq_printf(seq, ",errors=continue");
7095c5e32ceSMiklos Szeredi if (sbi->flag & JFS_ERR_PANIC)
7105c5e32ceSMiklos Szeredi seq_printf(seq, ",errors=panic");
7118fc2751bSMark Bellon
712115ff50bSDave Kleikamp #ifdef CONFIG_QUOTA
7138fc2751bSMark Bellon if (sbi->flag & JFS_USRQUOTA)
7148fc2751bSMark Bellon seq_puts(seq, ",usrquota");
7158fc2751bSMark Bellon
7168fc2751bSMark Bellon if (sbi->flag & JFS_GRPQUOTA)
7178fc2751bSMark Bellon seq_puts(seq, ",grpquota");
7188fc2751bSMark Bellon #endif
7198fc2751bSMark Bellon
7208fc2751bSMark Bellon return 0;
7218fc2751bSMark Bellon }
7228fc2751bSMark Bellon
723115ff50bSDave Kleikamp #ifdef CONFIG_QUOTA
724115ff50bSDave Kleikamp
725115ff50bSDave Kleikamp /* Read data from quotafile - avoid pagecache and such because we cannot afford
726115ff50bSDave Kleikamp * acquiring the locks... As quota files are never truncated and quota code
727115ff50bSDave Kleikamp * itself serializes the operations (and no one else should touch the files)
728115ff50bSDave Kleikamp * we don't have to be afraid of races */
jfs_quota_read(struct super_block * sb,int type,char * data,size_t len,loff_t off)729115ff50bSDave Kleikamp static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data,
730115ff50bSDave Kleikamp size_t len, loff_t off)
731115ff50bSDave Kleikamp {
732115ff50bSDave Kleikamp struct inode *inode = sb_dqopt(sb)->files[type];
733115ff50bSDave Kleikamp sector_t blk = off >> sb->s_blocksize_bits;
734115ff50bSDave Kleikamp int err = 0;
735115ff50bSDave Kleikamp int offset = off & (sb->s_blocksize - 1);
736115ff50bSDave Kleikamp int tocopy;
737115ff50bSDave Kleikamp size_t toread;
738115ff50bSDave Kleikamp struct buffer_head tmp_bh;
739115ff50bSDave Kleikamp struct buffer_head *bh;
740115ff50bSDave Kleikamp loff_t i_size = i_size_read(inode);
741115ff50bSDave Kleikamp
742115ff50bSDave Kleikamp if (off > i_size)
743115ff50bSDave Kleikamp return 0;
744115ff50bSDave Kleikamp if (off+len > i_size)
745115ff50bSDave Kleikamp len = i_size-off;
746115ff50bSDave Kleikamp toread = len;
747115ff50bSDave Kleikamp while (toread > 0) {
74873c6da32SJiangshan Yi tocopy = min_t(size_t, sb->s_blocksize - offset, toread);
749115ff50bSDave Kleikamp
750115ff50bSDave Kleikamp tmp_bh.b_state = 0;
75193407472SFabian Frederick tmp_bh.b_size = i_blocksize(inode);
752115ff50bSDave Kleikamp err = jfs_get_block(inode, blk, &tmp_bh, 0);
753115ff50bSDave Kleikamp if (err)
754115ff50bSDave Kleikamp return err;
755115ff50bSDave Kleikamp if (!buffer_mapped(&tmp_bh)) /* A hole? */
756115ff50bSDave Kleikamp memset(data, 0, tocopy);
757115ff50bSDave Kleikamp else {
758115ff50bSDave Kleikamp bh = sb_bread(sb, tmp_bh.b_blocknr);
759115ff50bSDave Kleikamp if (!bh)
760115ff50bSDave Kleikamp return -EIO;
761115ff50bSDave Kleikamp memcpy(data, bh->b_data+offset, tocopy);
762115ff50bSDave Kleikamp brelse(bh);
763115ff50bSDave Kleikamp }
764115ff50bSDave Kleikamp offset = 0;
765115ff50bSDave Kleikamp toread -= tocopy;
766115ff50bSDave Kleikamp data += tocopy;
767115ff50bSDave Kleikamp blk++;
768115ff50bSDave Kleikamp }
769115ff50bSDave Kleikamp return len;
770115ff50bSDave Kleikamp }
771115ff50bSDave Kleikamp
772115ff50bSDave Kleikamp /* Write to quotafile */
jfs_quota_write(struct super_block * sb,int type,const char * data,size_t len,loff_t off)773115ff50bSDave Kleikamp static ssize_t jfs_quota_write(struct super_block *sb, int type,
774115ff50bSDave Kleikamp const char *data, size_t len, loff_t off)
775115ff50bSDave Kleikamp {
776115ff50bSDave Kleikamp struct inode *inode = sb_dqopt(sb)->files[type];
777115ff50bSDave Kleikamp sector_t blk = off >> sb->s_blocksize_bits;
778115ff50bSDave Kleikamp int err = 0;
779115ff50bSDave Kleikamp int offset = off & (sb->s_blocksize - 1);
780115ff50bSDave Kleikamp int tocopy;
781115ff50bSDave Kleikamp size_t towrite = len;
782115ff50bSDave Kleikamp struct buffer_head tmp_bh;
783115ff50bSDave Kleikamp struct buffer_head *bh;
784115ff50bSDave Kleikamp
7855955102cSAl Viro inode_lock(inode);
786115ff50bSDave Kleikamp while (towrite > 0) {
78773c6da32SJiangshan Yi tocopy = min_t(size_t, sb->s_blocksize - offset, towrite);
788115ff50bSDave Kleikamp
789115ff50bSDave Kleikamp tmp_bh.b_state = 0;
79093407472SFabian Frederick tmp_bh.b_size = i_blocksize(inode);
791115ff50bSDave Kleikamp err = jfs_get_block(inode, blk, &tmp_bh, 1);
792115ff50bSDave Kleikamp if (err)
793115ff50bSDave Kleikamp goto out;
794115ff50bSDave Kleikamp if (offset || tocopy != sb->s_blocksize)
795115ff50bSDave Kleikamp bh = sb_bread(sb, tmp_bh.b_blocknr);
796115ff50bSDave Kleikamp else
797115ff50bSDave Kleikamp bh = sb_getblk(sb, tmp_bh.b_blocknr);
798115ff50bSDave Kleikamp if (!bh) {
799115ff50bSDave Kleikamp err = -EIO;
800115ff50bSDave Kleikamp goto out;
801115ff50bSDave Kleikamp }
802115ff50bSDave Kleikamp lock_buffer(bh);
803115ff50bSDave Kleikamp memcpy(bh->b_data+offset, data, tocopy);
804115ff50bSDave Kleikamp flush_dcache_page(bh->b_page);
805115ff50bSDave Kleikamp set_buffer_uptodate(bh);
806115ff50bSDave Kleikamp mark_buffer_dirty(bh);
807115ff50bSDave Kleikamp unlock_buffer(bh);
808115ff50bSDave Kleikamp brelse(bh);
809115ff50bSDave Kleikamp offset = 0;
810115ff50bSDave Kleikamp towrite -= tocopy;
811115ff50bSDave Kleikamp data += tocopy;
812115ff50bSDave Kleikamp blk++;
813115ff50bSDave Kleikamp }
814115ff50bSDave Kleikamp out:
8159c83633aSDan Carpenter if (len == towrite) {
8165955102cSAl Viro inode_unlock(inode);
817115ff50bSDave Kleikamp return err;
8189c83633aSDan Carpenter }
819115ff50bSDave Kleikamp if (inode->i_size < off+len-towrite)
820115ff50bSDave Kleikamp i_size_write(inode, off+len-towrite);
821ad9dc5dfSJeff Layton inode->i_mtime = inode_set_ctime_current(inode);
822115ff50bSDave Kleikamp mark_inode_dirty(inode);
8235955102cSAl Viro inode_unlock(inode);
824115ff50bSDave Kleikamp return len - towrite;
825115ff50bSDave Kleikamp }
826115ff50bSDave Kleikamp
jfs_get_dquots(struct inode * inode)827*42954c37SJan Kara static struct dquot __rcu **jfs_get_dquots(struct inode *inode)
828507e1fa6SJan Kara {
829507e1fa6SJan Kara return JFS_IP(inode)->i_dquot;
830507e1fa6SJan Kara }
83112fd086dSJan Kara
jfs_quota_on(struct super_block * sb,int type,int format_id,const struct path * path)83212fd086dSJan Kara static int jfs_quota_on(struct super_block *sb, int type, int format_id,
83312fd086dSJan Kara const struct path *path)
83412fd086dSJan Kara {
83512fd086dSJan Kara int err;
83612fd086dSJan Kara struct inode *inode;
83712fd086dSJan Kara
83812fd086dSJan Kara err = dquot_quota_on(sb, type, format_id, path);
83912fd086dSJan Kara if (err)
84012fd086dSJan Kara return err;
84112fd086dSJan Kara
84212fd086dSJan Kara inode = d_inode(path->dentry);
84312fd086dSJan Kara inode_lock(inode);
84412fd086dSJan Kara JFS_IP(inode)->mode2 |= JFS_NOATIME_FL | JFS_IMMUTABLE_FL;
84512fd086dSJan Kara inode_set_flags(inode, S_NOATIME | S_IMMUTABLE,
84612fd086dSJan Kara S_NOATIME | S_IMMUTABLE);
84712fd086dSJan Kara inode_unlock(inode);
84812fd086dSJan Kara mark_inode_dirty(inode);
84912fd086dSJan Kara
85012fd086dSJan Kara return 0;
85112fd086dSJan Kara }
85212fd086dSJan Kara
jfs_quota_off(struct super_block * sb,int type)85312fd086dSJan Kara static int jfs_quota_off(struct super_block *sb, int type)
85412fd086dSJan Kara {
85512fd086dSJan Kara struct inode *inode = sb_dqopt(sb)->files[type];
85612fd086dSJan Kara int err;
85712fd086dSJan Kara
85812fd086dSJan Kara if (!inode || !igrab(inode))
85912fd086dSJan Kara goto out;
86012fd086dSJan Kara
86112fd086dSJan Kara err = dquot_quota_off(sb, type);
86212fd086dSJan Kara if (err)
86312fd086dSJan Kara goto out_put;
86412fd086dSJan Kara
86512fd086dSJan Kara inode_lock(inode);
86612fd086dSJan Kara JFS_IP(inode)->mode2 &= ~(JFS_NOATIME_FL | JFS_IMMUTABLE_FL);
86712fd086dSJan Kara inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE);
86812fd086dSJan Kara inode_unlock(inode);
86912fd086dSJan Kara mark_inode_dirty(inode);
87012fd086dSJan Kara out_put:
87112fd086dSJan Kara iput(inode);
87212fd086dSJan Kara return err;
87312fd086dSJan Kara out:
87412fd086dSJan Kara return dquot_quota_off(sb, type);
87512fd086dSJan Kara }
876115ff50bSDave Kleikamp #endif
877115ff50bSDave Kleikamp
878ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jfs_super_operations = {
8791da177e4SLinus Torvalds .alloc_inode = jfs_alloc_inode,
880b3b4a6e3SAl Viro .free_inode = jfs_free_inode,
8811da177e4SLinus Torvalds .dirty_inode = jfs_dirty_inode,
8821da177e4SLinus Torvalds .write_inode = jfs_write_inode,
88362aff86fSAl Viro .evict_inode = jfs_evict_inode,
8841da177e4SLinus Torvalds .put_super = jfs_put_super,
8851da177e4SLinus Torvalds .sync_fs = jfs_sync_fs,
886c4be0c1dSTakashi Sato .freeze_fs = jfs_freeze,
887c4be0c1dSTakashi Sato .unfreeze_fs = jfs_unfreeze,
8881da177e4SLinus Torvalds .statfs = jfs_statfs,
8891da177e4SLinus Torvalds .remount_fs = jfs_remount,
890115ff50bSDave Kleikamp .show_options = jfs_show_options,
891115ff50bSDave Kleikamp #ifdef CONFIG_QUOTA
892115ff50bSDave Kleikamp .quota_read = jfs_quota_read,
893115ff50bSDave Kleikamp .quota_write = jfs_quota_write,
894507e1fa6SJan Kara .get_dquots = jfs_get_dquots,
895115ff50bSDave Kleikamp #endif
8961da177e4SLinus Torvalds };
8971da177e4SLinus Torvalds
89839655164SChristoph Hellwig static const struct export_operations jfs_export_operations = {
899d425de70SChristoph Hellwig .fh_to_dentry = jfs_fh_to_dentry,
900d425de70SChristoph Hellwig .fh_to_parent = jfs_fh_to_parent,
9011da177e4SLinus Torvalds .get_parent = jfs_get_parent,
9021da177e4SLinus Torvalds };
9031da177e4SLinus Torvalds
9041da177e4SLinus Torvalds static struct file_system_type jfs_fs_type = {
9051da177e4SLinus Torvalds .owner = THIS_MODULE,
9061da177e4SLinus Torvalds .name = "jfs",
907152a0836SAl Viro .mount = jfs_do_mount,
9081da177e4SLinus Torvalds .kill_sb = kill_block_super,
9091da177e4SLinus Torvalds .fs_flags = FS_REQUIRES_DEV,
9101da177e4SLinus Torvalds };
9117f78e035SEric W. Biederman MODULE_ALIAS_FS("jfs");
9121da177e4SLinus Torvalds
init_once(void * foo)91351cc5068SAlexey Dobriyan static void init_once(void *foo)
9141da177e4SLinus Torvalds {
9151da177e4SLinus Torvalds struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;
9161da177e4SLinus Torvalds
9171da177e4SLinus Torvalds memset(jfs_ip, 0, sizeof(struct jfs_inode_info));
9181da177e4SLinus Torvalds INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
9191da177e4SLinus Torvalds init_rwsem(&jfs_ip->rdwrlock);
9201de87444SIngo Molnar mutex_init(&jfs_ip->commit_mutex);
9211da177e4SLinus Torvalds init_rwsem(&jfs_ip->xattr_sem);
9221da177e4SLinus Torvalds spin_lock_init(&jfs_ip->ag_lock);
9231da177e4SLinus Torvalds jfs_ip->active_ag = -1;
9241da177e4SLinus Torvalds inode_init_once(&jfs_ip->vfs_inode);
9251da177e4SLinus Torvalds }
9261da177e4SLinus Torvalds
init_jfs_fs(void)9271da177e4SLinus Torvalds static int __init init_jfs_fs(void)
9281da177e4SLinus Torvalds {
9291da177e4SLinus Torvalds int i;
9301da177e4SLinus Torvalds int rc;
9311da177e4SLinus Torvalds
9321da177e4SLinus Torvalds jfs_inode_cachep =
9338d2704d3SDavid Windsor kmem_cache_create_usercopy("jfs_ip", sizeof(struct jfs_inode_info),
9348d2704d3SDavid Windsor 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
9355d299f44SKees Cook offsetof(struct jfs_inode_info, i_inline_all),
9365d299f44SKees Cook sizeof_field(struct jfs_inode_info, i_inline_all),
93720c2df83SPaul Mundt init_once);
9381da177e4SLinus Torvalds if (jfs_inode_cachep == NULL)
9391da177e4SLinus Torvalds return -ENOMEM;
9401da177e4SLinus Torvalds
9411da177e4SLinus Torvalds /*
9421da177e4SLinus Torvalds * Metapage initialization
9431da177e4SLinus Torvalds */
9441da177e4SLinus Torvalds rc = metapage_init();
9451da177e4SLinus Torvalds if (rc) {
9461da177e4SLinus Torvalds jfs_err("metapage_init failed w/rc = %d", rc);
9471da177e4SLinus Torvalds goto free_slab;
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds
9501da177e4SLinus Torvalds /*
9511da177e4SLinus Torvalds * Transaction Manager initialization
9521da177e4SLinus Torvalds */
9531da177e4SLinus Torvalds rc = txInit();
9541da177e4SLinus Torvalds if (rc) {
9551da177e4SLinus Torvalds jfs_err("txInit failed w/rc = %d", rc);
9561da177e4SLinus Torvalds goto free_metapage;
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds
9591da177e4SLinus Torvalds /*
9601da177e4SLinus Torvalds * I/O completion thread (endio)
9611da177e4SLinus Torvalds */
96291dbb4deSChristoph Hellwig jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO");
96391dbb4deSChristoph Hellwig if (IS_ERR(jfsIOthread)) {
96491dbb4deSChristoph Hellwig rc = PTR_ERR(jfsIOthread);
96591dbb4deSChristoph Hellwig jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
9661da177e4SLinus Torvalds goto end_txmngr;
9671da177e4SLinus Torvalds }
9681da177e4SLinus Torvalds
9691da177e4SLinus Torvalds if (commit_threads < 1)
9701da177e4SLinus Torvalds commit_threads = num_online_cpus();
9711da177e4SLinus Torvalds if (commit_threads > MAX_COMMIT_THREADS)
9721da177e4SLinus Torvalds commit_threads = MAX_COMMIT_THREADS;
9731da177e4SLinus Torvalds
9741da177e4SLinus Torvalds for (i = 0; i < commit_threads; i++) {
975789602e9SFabian Frederick jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL,
976789602e9SFabian Frederick "jfsCommit");
97791dbb4deSChristoph Hellwig if (IS_ERR(jfsCommitThread[i])) {
97891dbb4deSChristoph Hellwig rc = PTR_ERR(jfsCommitThread[i]);
97991dbb4deSChristoph Hellwig jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
9801da177e4SLinus Torvalds commit_threads = i;
9811da177e4SLinus Torvalds goto kill_committask;
9821da177e4SLinus Torvalds }
9831da177e4SLinus Torvalds }
9841da177e4SLinus Torvalds
98591dbb4deSChristoph Hellwig jfsSyncThread = kthread_run(jfs_sync, NULL, "jfsSync");
98691dbb4deSChristoph Hellwig if (IS_ERR(jfsSyncThread)) {
98791dbb4deSChristoph Hellwig rc = PTR_ERR(jfsSyncThread);
98891dbb4deSChristoph Hellwig jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
9891da177e4SLinus Torvalds goto kill_committask;
9901da177e4SLinus Torvalds }
9911da177e4SLinus Torvalds
9921da177e4SLinus Torvalds #ifdef PROC_FS_JFS
9931da177e4SLinus Torvalds jfs_proc_init();
9941da177e4SLinus Torvalds #endif
9951da177e4SLinus Torvalds
99676bf09fcSAl Viro rc = register_filesystem(&jfs_fs_type);
99776bf09fcSAl Viro if (!rc)
99876bf09fcSAl Viro return 0;
9991da177e4SLinus Torvalds
100076bf09fcSAl Viro #ifdef PROC_FS_JFS
100176bf09fcSAl Viro jfs_proc_clean();
100276bf09fcSAl Viro #endif
100376bf09fcSAl Viro kthread_stop(jfsSyncThread);
10041da177e4SLinus Torvalds kill_committask:
10051da177e4SLinus Torvalds for (i = 0; i < commit_threads; i++)
100691dbb4deSChristoph Hellwig kthread_stop(jfsCommitThread[i]);
100791dbb4deSChristoph Hellwig kthread_stop(jfsIOthread);
10081da177e4SLinus Torvalds end_txmngr:
10091da177e4SLinus Torvalds txExit();
10101da177e4SLinus Torvalds free_metapage:
10111da177e4SLinus Torvalds metapage_exit();
10121da177e4SLinus Torvalds free_slab:
10131da177e4SLinus Torvalds kmem_cache_destroy(jfs_inode_cachep);
10141da177e4SLinus Torvalds return rc;
10151da177e4SLinus Torvalds }
10161da177e4SLinus Torvalds
exit_jfs_fs(void)10171da177e4SLinus Torvalds static void __exit exit_jfs_fs(void)
10181da177e4SLinus Torvalds {
10191da177e4SLinus Torvalds int i;
10201da177e4SLinus Torvalds
10211da177e4SLinus Torvalds jfs_info("exit_jfs_fs called");
10221da177e4SLinus Torvalds
10231da177e4SLinus Torvalds txExit();
10241da177e4SLinus Torvalds metapage_exit();
102591dbb4deSChristoph Hellwig
102691dbb4deSChristoph Hellwig kthread_stop(jfsIOthread);
10271da177e4SLinus Torvalds for (i = 0; i < commit_threads; i++)
102891dbb4deSChristoph Hellwig kthread_stop(jfsCommitThread[i]);
102991dbb4deSChristoph Hellwig kthread_stop(jfsSyncThread);
10301da177e4SLinus Torvalds #ifdef PROC_FS_JFS
10311da177e4SLinus Torvalds jfs_proc_clean();
10321da177e4SLinus Torvalds #endif
10331da177e4SLinus Torvalds unregister_filesystem(&jfs_fs_type);
10348c0a8537SKirill A. Shutemov
10358c0a8537SKirill A. Shutemov /*
10368c0a8537SKirill A. Shutemov * Make sure all delayed rcu free inodes are flushed before we
10378c0a8537SKirill A. Shutemov * destroy cache.
10388c0a8537SKirill A. Shutemov */
10398c0a8537SKirill A. Shutemov rcu_barrier();
10401da177e4SLinus Torvalds kmem_cache_destroy(jfs_inode_cachep);
10411da177e4SLinus Torvalds }
10421da177e4SLinus Torvalds
10431da177e4SLinus Torvalds module_init(init_jfs_fs)
10441da177e4SLinus Torvalds module_exit(exit_jfs_fs)
1045