162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2000-2004 462306a36Sopenharmony_ci * Portions Copyright (C) Christoph Hellwig, 2001-2002 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/fs.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/parser.h> 1062306a36Sopenharmony_ci#include <linux/completion.h> 1162306a36Sopenharmony_ci#include <linux/vfs.h> 1262306a36Sopenharmony_ci#include <linux/quotaops.h> 1362306a36Sopenharmony_ci#include <linux/mount.h> 1462306a36Sopenharmony_ci#include <linux/moduleparam.h> 1562306a36Sopenharmony_ci#include <linux/kthread.h> 1662306a36Sopenharmony_ci#include <linux/posix_acl.h> 1762306a36Sopenharmony_ci#include <linux/buffer_head.h> 1862306a36Sopenharmony_ci#include <linux/exportfs.h> 1962306a36Sopenharmony_ci#include <linux/crc32.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/uaccess.h> 2262306a36Sopenharmony_ci#include <linux/seq_file.h> 2362306a36Sopenharmony_ci#include <linux/blkdev.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "jfs_incore.h" 2662306a36Sopenharmony_ci#include "jfs_filsys.h" 2762306a36Sopenharmony_ci#include "jfs_inode.h" 2862306a36Sopenharmony_ci#include "jfs_metapage.h" 2962306a36Sopenharmony_ci#include "jfs_superblock.h" 3062306a36Sopenharmony_ci#include "jfs_dmap.h" 3162306a36Sopenharmony_ci#include "jfs_imap.h" 3262306a36Sopenharmony_ci#include "jfs_acl.h" 3362306a36Sopenharmony_ci#include "jfs_debug.h" 3462306a36Sopenharmony_ci#include "jfs_xattr.h" 3562306a36Sopenharmony_ci#include "jfs_dinode.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciMODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); 3862306a36Sopenharmony_ciMODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM"); 3962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic struct kmem_cache *jfs_inode_cachep; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic const struct super_operations jfs_super_operations; 4462306a36Sopenharmony_cistatic const struct export_operations jfs_export_operations; 4562306a36Sopenharmony_cistatic struct file_system_type jfs_fs_type; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define MAX_COMMIT_THREADS 64 4862306a36Sopenharmony_cistatic int commit_threads; 4962306a36Sopenharmony_cimodule_param(commit_threads, int, 0); 5062306a36Sopenharmony_ciMODULE_PARM_DESC(commit_threads, "Number of commit threads"); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS]; 5362306a36Sopenharmony_cistruct task_struct *jfsIOthread; 5462306a36Sopenharmony_cistruct task_struct *jfsSyncThread; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#ifdef CONFIG_JFS_DEBUG 5762306a36Sopenharmony_ciint jfsloglevel = JFS_LOGLEVEL_WARN; 5862306a36Sopenharmony_cimodule_param(jfsloglevel, int, 0644); 5962306a36Sopenharmony_ciMODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)"); 6062306a36Sopenharmony_ci#endif 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void jfs_handle_error(struct super_block *sb) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(sb); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (sb_rdonly(sb)) 6762306a36Sopenharmony_ci return; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci updateSuper(sb, FM_DIRTY); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (sbi->flag & JFS_ERR_PANIC) 7262306a36Sopenharmony_ci panic("JFS (device %s): panic forced after error\n", 7362306a36Sopenharmony_ci sb->s_id); 7462306a36Sopenharmony_ci else if (sbi->flag & JFS_ERR_REMOUNT_RO) { 7562306a36Sopenharmony_ci jfs_err("ERROR: (device %s): remounting filesystem as read-only", 7662306a36Sopenharmony_ci sb->s_id); 7762306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* nothing is done for continue beyond marking the superblock dirty */ 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_civoid jfs_error(struct super_block *sb, const char *fmt, ...) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct va_format vaf; 8662306a36Sopenharmony_ci va_list args; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci va_start(args, fmt); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci vaf.fmt = fmt; 9162306a36Sopenharmony_ci vaf.va = &args; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci pr_err("ERROR: (device %s): %ps: %pV\n", 9462306a36Sopenharmony_ci sb->s_id, __builtin_return_address(0), &vaf); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci va_end(args); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci jfs_handle_error(sb); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic struct inode *jfs_alloc_inode(struct super_block *sb) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct jfs_inode_info *jfs_inode; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci jfs_inode = alloc_inode_sb(sb, jfs_inode_cachep, GFP_NOFS); 10662306a36Sopenharmony_ci if (!jfs_inode) 10762306a36Sopenharmony_ci return NULL; 10862306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 10962306a36Sopenharmony_ci memset(&jfs_inode->i_dquot, 0, sizeof(jfs_inode->i_dquot)); 11062306a36Sopenharmony_ci#endif 11162306a36Sopenharmony_ci return &jfs_inode->vfs_inode; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void jfs_free_inode(struct inode *inode) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci kmem_cache_free(jfs_inode_cachep, JFS_IP(inode)); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb); 12262306a36Sopenharmony_ci s64 maxinodes; 12362306a36Sopenharmony_ci struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci jfs_info("In jfs_statfs"); 12662306a36Sopenharmony_ci buf->f_type = JFS_SUPER_MAGIC; 12762306a36Sopenharmony_ci buf->f_bsize = sbi->bsize; 12862306a36Sopenharmony_ci buf->f_blocks = sbi->bmap->db_mapsize; 12962306a36Sopenharmony_ci buf->f_bfree = sbi->bmap->db_nfree; 13062306a36Sopenharmony_ci buf->f_bavail = sbi->bmap->db_nfree; 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * If we really return the number of allocated & free inodes, some 13362306a36Sopenharmony_ci * applications will fail because they won't see enough free inodes. 13462306a36Sopenharmony_ci * We'll try to calculate some guess as to how many inodes we can 13562306a36Sopenharmony_ci * really allocate 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * buf->f_files = atomic_read(&imap->im_numinos); 13862306a36Sopenharmony_ci * buf->f_ffree = atomic_read(&imap->im_numfree); 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci maxinodes = min((s64) atomic_read(&imap->im_numinos) + 14162306a36Sopenharmony_ci ((sbi->bmap->db_nfree >> imap->im_l2nbperiext) 14262306a36Sopenharmony_ci << L2INOSPEREXT), (s64) 0xffffffffLL); 14362306a36Sopenharmony_ci buf->f_files = maxinodes; 14462306a36Sopenharmony_ci buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) - 14562306a36Sopenharmony_ci atomic_read(&imap->im_numfree)); 14662306a36Sopenharmony_ci buf->f_fsid.val[0] = crc32_le(0, (char *)&sbi->uuid, 14762306a36Sopenharmony_ci sizeof(sbi->uuid)/2); 14862306a36Sopenharmony_ci buf->f_fsid.val[1] = crc32_le(0, 14962306a36Sopenharmony_ci (char *)&sbi->uuid + sizeof(sbi->uuid)/2, 15062306a36Sopenharmony_ci sizeof(sbi->uuid)/2); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci buf->f_namelen = JFS_NAME_MAX; 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 15762306a36Sopenharmony_cistatic int jfs_quota_off(struct super_block *sb, int type); 15862306a36Sopenharmony_cistatic int jfs_quota_on(struct super_block *sb, int type, int format_id, 15962306a36Sopenharmony_ci const struct path *path); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void jfs_quota_off_umount(struct super_block *sb) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci int type; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) 16662306a36Sopenharmony_ci jfs_quota_off(sb, type); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic const struct quotactl_ops jfs_quotactl_ops = { 17062306a36Sopenharmony_ci .quota_on = jfs_quota_on, 17162306a36Sopenharmony_ci .quota_off = jfs_quota_off, 17262306a36Sopenharmony_ci .quota_sync = dquot_quota_sync, 17362306a36Sopenharmony_ci .get_state = dquot_get_state, 17462306a36Sopenharmony_ci .set_info = dquot_set_dqinfo, 17562306a36Sopenharmony_ci .get_dqblk = dquot_get_dqblk, 17662306a36Sopenharmony_ci .set_dqblk = dquot_set_dqblk, 17762306a36Sopenharmony_ci .get_nextdqblk = dquot_get_next_dqblk, 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci#else 18062306a36Sopenharmony_cistatic inline void jfs_quota_off_umount(struct super_block *sb) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci#endif 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void jfs_put_super(struct super_block *sb) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(sb); 18862306a36Sopenharmony_ci int rc; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci jfs_info("In jfs_put_super"); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci jfs_quota_off_umount(sb); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci rc = jfs_umount(sb); 19562306a36Sopenharmony_ci if (rc) 19662306a36Sopenharmony_ci jfs_err("jfs_umount failed with return code %d", rc); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci unload_nls(sbi->nls_tab); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci truncate_inode_pages(sbi->direct_inode->i_mapping, 0); 20162306a36Sopenharmony_ci iput(sbi->direct_inode); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci kfree(sbi); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cienum { 20762306a36Sopenharmony_ci Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, 20862306a36Sopenharmony_ci Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, 20962306a36Sopenharmony_ci Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask, 21062306a36Sopenharmony_ci Opt_discard, Opt_nodiscard, Opt_discard_minblk 21162306a36Sopenharmony_ci}; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic const match_table_t tokens = { 21462306a36Sopenharmony_ci {Opt_integrity, "integrity"}, 21562306a36Sopenharmony_ci {Opt_nointegrity, "nointegrity"}, 21662306a36Sopenharmony_ci {Opt_iocharset, "iocharset=%s"}, 21762306a36Sopenharmony_ci {Opt_resize, "resize=%u"}, 21862306a36Sopenharmony_ci {Opt_resize_nosize, "resize"}, 21962306a36Sopenharmony_ci {Opt_errors, "errors=%s"}, 22062306a36Sopenharmony_ci {Opt_ignore, "noquota"}, 22162306a36Sopenharmony_ci {Opt_quota, "quota"}, 22262306a36Sopenharmony_ci {Opt_usrquota, "usrquota"}, 22362306a36Sopenharmony_ci {Opt_grpquota, "grpquota"}, 22462306a36Sopenharmony_ci {Opt_uid, "uid=%u"}, 22562306a36Sopenharmony_ci {Opt_gid, "gid=%u"}, 22662306a36Sopenharmony_ci {Opt_umask, "umask=%u"}, 22762306a36Sopenharmony_ci {Opt_discard, "discard"}, 22862306a36Sopenharmony_ci {Opt_nodiscard, "nodiscard"}, 22962306a36Sopenharmony_ci {Opt_discard_minblk, "discard=%u"}, 23062306a36Sopenharmony_ci {Opt_err, NULL} 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int parse_options(char *options, struct super_block *sb, s64 *newLVSize, 23462306a36Sopenharmony_ci int *flag) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci void *nls_map = (void *)-1; /* -1: no change; NULL: none */ 23762306a36Sopenharmony_ci char *p; 23862306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(sb); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci *newLVSize = 0; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (!options) 24362306a36Sopenharmony_ci return 1; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 24662306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 24762306a36Sopenharmony_ci int token; 24862306a36Sopenharmony_ci if (!*p) 24962306a36Sopenharmony_ci continue; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci token = match_token(p, tokens, args); 25262306a36Sopenharmony_ci switch (token) { 25362306a36Sopenharmony_ci case Opt_integrity: 25462306a36Sopenharmony_ci *flag &= ~JFS_NOINTEGRITY; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci case Opt_nointegrity: 25762306a36Sopenharmony_ci *flag |= JFS_NOINTEGRITY; 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case Opt_ignore: 26062306a36Sopenharmony_ci /* Silently ignore the quota options */ 26162306a36Sopenharmony_ci /* Don't do anything ;-) */ 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci case Opt_iocharset: 26462306a36Sopenharmony_ci if (nls_map && nls_map != (void *) -1) 26562306a36Sopenharmony_ci unload_nls(nls_map); 26662306a36Sopenharmony_ci if (!strcmp(args[0].from, "none")) 26762306a36Sopenharmony_ci nls_map = NULL; 26862306a36Sopenharmony_ci else { 26962306a36Sopenharmony_ci nls_map = load_nls(args[0].from); 27062306a36Sopenharmony_ci if (!nls_map) { 27162306a36Sopenharmony_ci pr_err("JFS: charset not found\n"); 27262306a36Sopenharmony_ci goto cleanup; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci case Opt_resize: 27762306a36Sopenharmony_ci { 27862306a36Sopenharmony_ci char *resize = args[0].from; 27962306a36Sopenharmony_ci int rc = kstrtoll(resize, 0, newLVSize); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (rc) 28262306a36Sopenharmony_ci goto cleanup; 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci case Opt_resize_nosize: 28662306a36Sopenharmony_ci { 28762306a36Sopenharmony_ci *newLVSize = sb_bdev_nr_blocks(sb); 28862306a36Sopenharmony_ci if (*newLVSize == 0) 28962306a36Sopenharmony_ci pr_err("JFS: Cannot determine volume size\n"); 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci case Opt_errors: 29362306a36Sopenharmony_ci { 29462306a36Sopenharmony_ci char *errors = args[0].from; 29562306a36Sopenharmony_ci if (!errors || !*errors) 29662306a36Sopenharmony_ci goto cleanup; 29762306a36Sopenharmony_ci if (!strcmp(errors, "continue")) { 29862306a36Sopenharmony_ci *flag &= ~JFS_ERR_REMOUNT_RO; 29962306a36Sopenharmony_ci *flag &= ~JFS_ERR_PANIC; 30062306a36Sopenharmony_ci *flag |= JFS_ERR_CONTINUE; 30162306a36Sopenharmony_ci } else if (!strcmp(errors, "remount-ro")) { 30262306a36Sopenharmony_ci *flag &= ~JFS_ERR_CONTINUE; 30362306a36Sopenharmony_ci *flag &= ~JFS_ERR_PANIC; 30462306a36Sopenharmony_ci *flag |= JFS_ERR_REMOUNT_RO; 30562306a36Sopenharmony_ci } else if (!strcmp(errors, "panic")) { 30662306a36Sopenharmony_ci *flag &= ~JFS_ERR_CONTINUE; 30762306a36Sopenharmony_ci *flag &= ~JFS_ERR_REMOUNT_RO; 30862306a36Sopenharmony_ci *flag |= JFS_ERR_PANIC; 30962306a36Sopenharmony_ci } else { 31062306a36Sopenharmony_ci pr_err("JFS: %s is an invalid error handler\n", 31162306a36Sopenharmony_ci errors); 31262306a36Sopenharmony_ci goto cleanup; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci break; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 31862306a36Sopenharmony_ci case Opt_quota: 31962306a36Sopenharmony_ci case Opt_usrquota: 32062306a36Sopenharmony_ci *flag |= JFS_USRQUOTA; 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci case Opt_grpquota: 32362306a36Sopenharmony_ci *flag |= JFS_GRPQUOTA; 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci#else 32662306a36Sopenharmony_ci case Opt_usrquota: 32762306a36Sopenharmony_ci case Opt_grpquota: 32862306a36Sopenharmony_ci case Opt_quota: 32962306a36Sopenharmony_ci pr_err("JFS: quota operations not supported\n"); 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci#endif 33262306a36Sopenharmony_ci case Opt_uid: 33362306a36Sopenharmony_ci { 33462306a36Sopenharmony_ci char *uid = args[0].from; 33562306a36Sopenharmony_ci uid_t val; 33662306a36Sopenharmony_ci int rc = kstrtouint(uid, 0, &val); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (rc) 33962306a36Sopenharmony_ci goto cleanup; 34062306a36Sopenharmony_ci sbi->uid = make_kuid(current_user_ns(), val); 34162306a36Sopenharmony_ci if (!uid_valid(sbi->uid)) 34262306a36Sopenharmony_ci goto cleanup; 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci case Opt_gid: 34762306a36Sopenharmony_ci { 34862306a36Sopenharmony_ci char *gid = args[0].from; 34962306a36Sopenharmony_ci gid_t val; 35062306a36Sopenharmony_ci int rc = kstrtouint(gid, 0, &val); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (rc) 35362306a36Sopenharmony_ci goto cleanup; 35462306a36Sopenharmony_ci sbi->gid = make_kgid(current_user_ns(), val); 35562306a36Sopenharmony_ci if (!gid_valid(sbi->gid)) 35662306a36Sopenharmony_ci goto cleanup; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci case Opt_umask: 36162306a36Sopenharmony_ci { 36262306a36Sopenharmony_ci char *umask = args[0].from; 36362306a36Sopenharmony_ci int rc = kstrtouint(umask, 8, &sbi->umask); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (rc) 36662306a36Sopenharmony_ci goto cleanup; 36762306a36Sopenharmony_ci if (sbi->umask & ~0777) { 36862306a36Sopenharmony_ci pr_err("JFS: Invalid value of umask\n"); 36962306a36Sopenharmony_ci goto cleanup; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci break; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci case Opt_discard: 37562306a36Sopenharmony_ci /* if set to 1, even copying files will cause 37662306a36Sopenharmony_ci * trimming :O 37762306a36Sopenharmony_ci * -> user has more control over the online trimming 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci sbi->minblks_trim = 64; 38062306a36Sopenharmony_ci if (bdev_max_discard_sectors(sb->s_bdev)) 38162306a36Sopenharmony_ci *flag |= JFS_DISCARD; 38262306a36Sopenharmony_ci else 38362306a36Sopenharmony_ci pr_err("JFS: discard option not supported on device\n"); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci case Opt_nodiscard: 38762306a36Sopenharmony_ci *flag &= ~JFS_DISCARD; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci case Opt_discard_minblk: 39162306a36Sopenharmony_ci { 39262306a36Sopenharmony_ci char *minblks_trim = args[0].from; 39362306a36Sopenharmony_ci int rc; 39462306a36Sopenharmony_ci if (bdev_max_discard_sectors(sb->s_bdev)) { 39562306a36Sopenharmony_ci *flag |= JFS_DISCARD; 39662306a36Sopenharmony_ci rc = kstrtouint(minblks_trim, 0, 39762306a36Sopenharmony_ci &sbi->minblks_trim); 39862306a36Sopenharmony_ci if (rc) 39962306a36Sopenharmony_ci goto cleanup; 40062306a36Sopenharmony_ci } else 40162306a36Sopenharmony_ci pr_err("JFS: discard option not supported on device\n"); 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci default: 40662306a36Sopenharmony_ci printk("jfs: Unrecognized mount option \"%s\" or missing value\n", 40762306a36Sopenharmony_ci p); 40862306a36Sopenharmony_ci goto cleanup; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (nls_map != (void *) -1) { 41362306a36Sopenharmony_ci /* Discard old (if remount) */ 41462306a36Sopenharmony_ci unload_nls(sbi->nls_tab); 41562306a36Sopenharmony_ci sbi->nls_tab = nls_map; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci return 1; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cicleanup: 42062306a36Sopenharmony_ci if (nls_map && nls_map != (void *) -1) 42162306a36Sopenharmony_ci unload_nls(nls_map); 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int jfs_remount(struct super_block *sb, int *flags, char *data) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci s64 newLVSize = 0; 42862306a36Sopenharmony_ci int rc = 0; 42962306a36Sopenharmony_ci int flag = JFS_SBI(sb)->flag; 43062306a36Sopenharmony_ci int ret; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci sync_filesystem(sb); 43362306a36Sopenharmony_ci if (!parse_options(data, sb, &newLVSize, &flag)) 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (newLVSize) { 43762306a36Sopenharmony_ci if (sb_rdonly(sb)) { 43862306a36Sopenharmony_ci pr_err("JFS: resize requires volume to be mounted read-write\n"); 43962306a36Sopenharmony_ci return -EROFS; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci rc = jfs_extendfs(sb, newLVSize, 0); 44262306a36Sopenharmony_ci if (rc) 44362306a36Sopenharmony_ci return rc; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (sb_rdonly(sb) && !(*flags & SB_RDONLY)) { 44762306a36Sopenharmony_ci /* 44862306a36Sopenharmony_ci * Invalidate any previously read metadata. fsck may have 44962306a36Sopenharmony_ci * changed the on-disk data since we mounted r/o 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_ci truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci JFS_SBI(sb)->flag = flag; 45462306a36Sopenharmony_ci ret = jfs_mount_rw(sb, 1); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* mark the fs r/w for quota activity */ 45762306a36Sopenharmony_ci sb->s_flags &= ~SB_RDONLY; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci dquot_resume(sb, -1); 46062306a36Sopenharmony_ci return ret; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci if (!sb_rdonly(sb) && (*flags & SB_RDONLY)) { 46362306a36Sopenharmony_ci rc = dquot_suspend(sb, -1); 46462306a36Sopenharmony_ci if (rc < 0) 46562306a36Sopenharmony_ci return rc; 46662306a36Sopenharmony_ci rc = jfs_umount_rw(sb); 46762306a36Sopenharmony_ci JFS_SBI(sb)->flag = flag; 46862306a36Sopenharmony_ci return rc; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY)) 47162306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 47262306a36Sopenharmony_ci rc = jfs_umount_rw(sb); 47362306a36Sopenharmony_ci if (rc) 47462306a36Sopenharmony_ci return rc; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci JFS_SBI(sb)->flag = flag; 47762306a36Sopenharmony_ci ret = jfs_mount_rw(sb, 1); 47862306a36Sopenharmony_ci return ret; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci JFS_SBI(sb)->flag = flag; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int jfs_fill_super(struct super_block *sb, void *data, int silent) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct jfs_sb_info *sbi; 48862306a36Sopenharmony_ci struct inode *inode; 48962306a36Sopenharmony_ci int rc; 49062306a36Sopenharmony_ci s64 newLVSize = 0; 49162306a36Sopenharmony_ci int flag, ret = -EINVAL; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci sbi = kzalloc(sizeof(struct jfs_sb_info), GFP_KERNEL); 49662306a36Sopenharmony_ci if (!sbi) 49762306a36Sopenharmony_ci return -ENOMEM; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci sb->s_fs_info = sbi; 50062306a36Sopenharmony_ci sb->s_max_links = JFS_LINK_MAX; 50162306a36Sopenharmony_ci sb->s_time_min = 0; 50262306a36Sopenharmony_ci sb->s_time_max = U32_MAX; 50362306a36Sopenharmony_ci sbi->sb = sb; 50462306a36Sopenharmony_ci sbi->uid = INVALID_UID; 50562306a36Sopenharmony_ci sbi->gid = INVALID_GID; 50662306a36Sopenharmony_ci sbi->umask = -1; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* initialize the mount flag and determine the default error handler */ 50962306a36Sopenharmony_ci flag = JFS_ERR_REMOUNT_RO; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (!parse_options((char *) data, sb, &newLVSize, &flag)) 51262306a36Sopenharmony_ci goto out_kfree; 51362306a36Sopenharmony_ci sbi->flag = flag; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci#ifdef CONFIG_JFS_POSIX_ACL 51662306a36Sopenharmony_ci sb->s_flags |= SB_POSIXACL; 51762306a36Sopenharmony_ci#endif 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (newLVSize) { 52062306a36Sopenharmony_ci pr_err("resize option for remount only\n"); 52162306a36Sopenharmony_ci goto out_kfree; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* 52562306a36Sopenharmony_ci * Initialize blocksize to 4K. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ci sb_set_blocksize(sb, PSIZE); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* 53062306a36Sopenharmony_ci * Set method vectors. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci sb->s_op = &jfs_super_operations; 53362306a36Sopenharmony_ci sb->s_export_op = &jfs_export_operations; 53462306a36Sopenharmony_ci sb->s_xattr = jfs_xattr_handlers; 53562306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 53662306a36Sopenharmony_ci sb->dq_op = &dquot_operations; 53762306a36Sopenharmony_ci sb->s_qcop = &jfs_quotactl_ops; 53862306a36Sopenharmony_ci sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP; 53962306a36Sopenharmony_ci#endif 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* 54262306a36Sopenharmony_ci * Initialize direct-mapping inode/address-space 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_ci inode = new_inode(sb); 54562306a36Sopenharmony_ci if (inode == NULL) { 54662306a36Sopenharmony_ci ret = -ENOMEM; 54762306a36Sopenharmony_ci goto out_unload; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci inode->i_size = bdev_nr_bytes(sb->s_bdev); 55062306a36Sopenharmony_ci inode->i_mapping->a_ops = &jfs_metapage_aops; 55162306a36Sopenharmony_ci inode_fake_hash(inode); 55262306a36Sopenharmony_ci mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci sbi->direct_inode = inode; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci rc = jfs_mount(sb); 55762306a36Sopenharmony_ci if (rc) { 55862306a36Sopenharmony_ci if (!silent) 55962306a36Sopenharmony_ci jfs_err("jfs_mount failed w/return code = %d", rc); 56062306a36Sopenharmony_ci goto out_mount_failed; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci if (sb_rdonly(sb)) 56362306a36Sopenharmony_ci sbi->log = NULL; 56462306a36Sopenharmony_ci else { 56562306a36Sopenharmony_ci rc = jfs_mount_rw(sb, 0); 56662306a36Sopenharmony_ci if (rc) { 56762306a36Sopenharmony_ci if (!silent) { 56862306a36Sopenharmony_ci jfs_err("jfs_mount_rw failed, return code = %d", 56962306a36Sopenharmony_ci rc); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci goto out_no_rw; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci sb->s_magic = JFS_SUPER_MAGIC; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (sbi->mntflag & JFS_OS2) 57862306a36Sopenharmony_ci sb->s_d_op = &jfs_ci_dentry_operations; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci inode = jfs_iget(sb, ROOT_I); 58162306a36Sopenharmony_ci if (IS_ERR(inode)) { 58262306a36Sopenharmony_ci ret = PTR_ERR(inode); 58362306a36Sopenharmony_ci goto out_no_rw; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci sb->s_root = d_make_root(inode); 58662306a36Sopenharmony_ci if (!sb->s_root) 58762306a36Sopenharmony_ci goto out_no_root; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* logical blocks are represented by 40 bits in pxd_t, etc. 59062306a36Sopenharmony_ci * and page cache is indexed by long 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci sb->s_maxbytes = min(((loff_t)sb->s_blocksize) << 40, MAX_LFS_FILESIZE); 59362306a36Sopenharmony_ci sb->s_time_gran = 1; 59462306a36Sopenharmony_ci return 0; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ciout_no_root: 59762306a36Sopenharmony_ci jfs_err("jfs_read_super: get root dentry failed"); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ciout_no_rw: 60062306a36Sopenharmony_ci rc = jfs_umount(sb); 60162306a36Sopenharmony_ci if (rc) 60262306a36Sopenharmony_ci jfs_err("jfs_umount failed with return code %d", rc); 60362306a36Sopenharmony_ciout_mount_failed: 60462306a36Sopenharmony_ci filemap_write_and_wait(sbi->direct_inode->i_mapping); 60562306a36Sopenharmony_ci truncate_inode_pages(sbi->direct_inode->i_mapping, 0); 60662306a36Sopenharmony_ci make_bad_inode(sbi->direct_inode); 60762306a36Sopenharmony_ci iput(sbi->direct_inode); 60862306a36Sopenharmony_ci sbi->direct_inode = NULL; 60962306a36Sopenharmony_ciout_unload: 61062306a36Sopenharmony_ci unload_nls(sbi->nls_tab); 61162306a36Sopenharmony_ciout_kfree: 61262306a36Sopenharmony_ci kfree(sbi); 61362306a36Sopenharmony_ci return ret; 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic int jfs_freeze(struct super_block *sb) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(sb); 61962306a36Sopenharmony_ci struct jfs_log *log = sbi->log; 62062306a36Sopenharmony_ci int rc = 0; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 62362306a36Sopenharmony_ci txQuiesce(sb); 62462306a36Sopenharmony_ci rc = lmLogShutdown(log); 62562306a36Sopenharmony_ci if (rc) { 62662306a36Sopenharmony_ci jfs_error(sb, "lmLogShutdown failed\n"); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* let operations fail rather than hang */ 62962306a36Sopenharmony_ci txResume(sb); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return rc; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci rc = updateSuper(sb, FM_CLEAN); 63462306a36Sopenharmony_ci if (rc) { 63562306a36Sopenharmony_ci jfs_err("jfs_freeze: updateSuper failed"); 63662306a36Sopenharmony_ci /* 63762306a36Sopenharmony_ci * Don't fail here. Everything succeeded except 63862306a36Sopenharmony_ci * marking the superblock clean, so there's really 63962306a36Sopenharmony_ci * no harm in leaving it frozen for now. 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int jfs_unfreeze(struct super_block *sb) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(sb); 64962306a36Sopenharmony_ci struct jfs_log *log = sbi->log; 65062306a36Sopenharmony_ci int rc = 0; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 65362306a36Sopenharmony_ci rc = updateSuper(sb, FM_MOUNT); 65462306a36Sopenharmony_ci if (rc) { 65562306a36Sopenharmony_ci jfs_error(sb, "updateSuper failed\n"); 65662306a36Sopenharmony_ci goto out; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci rc = lmLogInit(log); 65962306a36Sopenharmony_ci if (rc) 66062306a36Sopenharmony_ci jfs_error(sb, "lmLogInit failed\n"); 66162306a36Sopenharmony_ciout: 66262306a36Sopenharmony_ci txResume(sb); 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci return rc; 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic struct dentry *jfs_do_mount(struct file_system_type *fs_type, 66862306a36Sopenharmony_ci int flags, const char *dev_name, void *data) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, jfs_fill_super); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int jfs_sync_fs(struct super_block *sb, int wait) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct jfs_log *log = JFS_SBI(sb)->log; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* log == NULL indicates read-only mount */ 67862306a36Sopenharmony_ci if (log) { 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * Write quota structures to quota file, sync_blockdev() will 68162306a36Sopenharmony_ci * write them to disk later 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci dquot_writeback_dquots(sb, -1); 68462306a36Sopenharmony_ci jfs_flush_journal(log, wait); 68562306a36Sopenharmony_ci jfs_syncpt(log, 0); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci return 0; 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic int jfs_show_options(struct seq_file *seq, struct dentry *root) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(root->d_sb); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (uid_valid(sbi->uid)) 69662306a36Sopenharmony_ci seq_printf(seq, ",uid=%d", from_kuid(&init_user_ns, sbi->uid)); 69762306a36Sopenharmony_ci if (gid_valid(sbi->gid)) 69862306a36Sopenharmony_ci seq_printf(seq, ",gid=%d", from_kgid(&init_user_ns, sbi->gid)); 69962306a36Sopenharmony_ci if (sbi->umask != -1) 70062306a36Sopenharmony_ci seq_printf(seq, ",umask=%03o", sbi->umask); 70162306a36Sopenharmony_ci if (sbi->flag & JFS_NOINTEGRITY) 70262306a36Sopenharmony_ci seq_puts(seq, ",nointegrity"); 70362306a36Sopenharmony_ci if (sbi->flag & JFS_DISCARD) 70462306a36Sopenharmony_ci seq_printf(seq, ",discard=%u", sbi->minblks_trim); 70562306a36Sopenharmony_ci if (sbi->nls_tab) 70662306a36Sopenharmony_ci seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset); 70762306a36Sopenharmony_ci if (sbi->flag & JFS_ERR_CONTINUE) 70862306a36Sopenharmony_ci seq_printf(seq, ",errors=continue"); 70962306a36Sopenharmony_ci if (sbi->flag & JFS_ERR_PANIC) 71062306a36Sopenharmony_ci seq_printf(seq, ",errors=panic"); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 71362306a36Sopenharmony_ci if (sbi->flag & JFS_USRQUOTA) 71462306a36Sopenharmony_ci seq_puts(seq, ",usrquota"); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (sbi->flag & JFS_GRPQUOTA) 71762306a36Sopenharmony_ci seq_puts(seq, ",grpquota"); 71862306a36Sopenharmony_ci#endif 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return 0; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci/* Read data from quotafile - avoid pagecache and such because we cannot afford 72662306a36Sopenharmony_ci * acquiring the locks... As quota files are never truncated and quota code 72762306a36Sopenharmony_ci * itself serializes the operations (and no one else should touch the files) 72862306a36Sopenharmony_ci * we don't have to be afraid of races */ 72962306a36Sopenharmony_cistatic ssize_t jfs_quota_read(struct super_block *sb, int type, char *data, 73062306a36Sopenharmony_ci size_t len, loff_t off) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 73362306a36Sopenharmony_ci sector_t blk = off >> sb->s_blocksize_bits; 73462306a36Sopenharmony_ci int err = 0; 73562306a36Sopenharmony_ci int offset = off & (sb->s_blocksize - 1); 73662306a36Sopenharmony_ci int tocopy; 73762306a36Sopenharmony_ci size_t toread; 73862306a36Sopenharmony_ci struct buffer_head tmp_bh; 73962306a36Sopenharmony_ci struct buffer_head *bh; 74062306a36Sopenharmony_ci loff_t i_size = i_size_read(inode); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (off > i_size) 74362306a36Sopenharmony_ci return 0; 74462306a36Sopenharmony_ci if (off+len > i_size) 74562306a36Sopenharmony_ci len = i_size-off; 74662306a36Sopenharmony_ci toread = len; 74762306a36Sopenharmony_ci while (toread > 0) { 74862306a36Sopenharmony_ci tocopy = min_t(size_t, sb->s_blocksize - offset, toread); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci tmp_bh.b_state = 0; 75162306a36Sopenharmony_ci tmp_bh.b_size = i_blocksize(inode); 75262306a36Sopenharmony_ci err = jfs_get_block(inode, blk, &tmp_bh, 0); 75362306a36Sopenharmony_ci if (err) 75462306a36Sopenharmony_ci return err; 75562306a36Sopenharmony_ci if (!buffer_mapped(&tmp_bh)) /* A hole? */ 75662306a36Sopenharmony_ci memset(data, 0, tocopy); 75762306a36Sopenharmony_ci else { 75862306a36Sopenharmony_ci bh = sb_bread(sb, tmp_bh.b_blocknr); 75962306a36Sopenharmony_ci if (!bh) 76062306a36Sopenharmony_ci return -EIO; 76162306a36Sopenharmony_ci memcpy(data, bh->b_data+offset, tocopy); 76262306a36Sopenharmony_ci brelse(bh); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci offset = 0; 76562306a36Sopenharmony_ci toread -= tocopy; 76662306a36Sopenharmony_ci data += tocopy; 76762306a36Sopenharmony_ci blk++; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci return len; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci/* Write to quotafile */ 77362306a36Sopenharmony_cistatic ssize_t jfs_quota_write(struct super_block *sb, int type, 77462306a36Sopenharmony_ci const char *data, size_t len, loff_t off) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 77762306a36Sopenharmony_ci sector_t blk = off >> sb->s_blocksize_bits; 77862306a36Sopenharmony_ci int err = 0; 77962306a36Sopenharmony_ci int offset = off & (sb->s_blocksize - 1); 78062306a36Sopenharmony_ci int tocopy; 78162306a36Sopenharmony_ci size_t towrite = len; 78262306a36Sopenharmony_ci struct buffer_head tmp_bh; 78362306a36Sopenharmony_ci struct buffer_head *bh; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci inode_lock(inode); 78662306a36Sopenharmony_ci while (towrite > 0) { 78762306a36Sopenharmony_ci tocopy = min_t(size_t, sb->s_blocksize - offset, towrite); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci tmp_bh.b_state = 0; 79062306a36Sopenharmony_ci tmp_bh.b_size = i_blocksize(inode); 79162306a36Sopenharmony_ci err = jfs_get_block(inode, blk, &tmp_bh, 1); 79262306a36Sopenharmony_ci if (err) 79362306a36Sopenharmony_ci goto out; 79462306a36Sopenharmony_ci if (offset || tocopy != sb->s_blocksize) 79562306a36Sopenharmony_ci bh = sb_bread(sb, tmp_bh.b_blocknr); 79662306a36Sopenharmony_ci else 79762306a36Sopenharmony_ci bh = sb_getblk(sb, tmp_bh.b_blocknr); 79862306a36Sopenharmony_ci if (!bh) { 79962306a36Sopenharmony_ci err = -EIO; 80062306a36Sopenharmony_ci goto out; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci lock_buffer(bh); 80362306a36Sopenharmony_ci memcpy(bh->b_data+offset, data, tocopy); 80462306a36Sopenharmony_ci flush_dcache_page(bh->b_page); 80562306a36Sopenharmony_ci set_buffer_uptodate(bh); 80662306a36Sopenharmony_ci mark_buffer_dirty(bh); 80762306a36Sopenharmony_ci unlock_buffer(bh); 80862306a36Sopenharmony_ci brelse(bh); 80962306a36Sopenharmony_ci offset = 0; 81062306a36Sopenharmony_ci towrite -= tocopy; 81162306a36Sopenharmony_ci data += tocopy; 81262306a36Sopenharmony_ci blk++; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ciout: 81562306a36Sopenharmony_ci if (len == towrite) { 81662306a36Sopenharmony_ci inode_unlock(inode); 81762306a36Sopenharmony_ci return err; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci if (inode->i_size < off+len-towrite) 82062306a36Sopenharmony_ci i_size_write(inode, off+len-towrite); 82162306a36Sopenharmony_ci inode->i_mtime = inode_set_ctime_current(inode); 82262306a36Sopenharmony_ci mark_inode_dirty(inode); 82362306a36Sopenharmony_ci inode_unlock(inode); 82462306a36Sopenharmony_ci return len - towrite; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic struct dquot __rcu **jfs_get_dquots(struct inode *inode) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci return JFS_IP(inode)->i_dquot; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic int jfs_quota_on(struct super_block *sb, int type, int format_id, 83362306a36Sopenharmony_ci const struct path *path) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci int err; 83662306a36Sopenharmony_ci struct inode *inode; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci err = dquot_quota_on(sb, type, format_id, path); 83962306a36Sopenharmony_ci if (err) 84062306a36Sopenharmony_ci return err; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci inode = d_inode(path->dentry); 84362306a36Sopenharmony_ci inode_lock(inode); 84462306a36Sopenharmony_ci JFS_IP(inode)->mode2 |= JFS_NOATIME_FL | JFS_IMMUTABLE_FL; 84562306a36Sopenharmony_ci inode_set_flags(inode, S_NOATIME | S_IMMUTABLE, 84662306a36Sopenharmony_ci S_NOATIME | S_IMMUTABLE); 84762306a36Sopenharmony_ci inode_unlock(inode); 84862306a36Sopenharmony_ci mark_inode_dirty(inode); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci return 0; 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic int jfs_quota_off(struct super_block *sb, int type) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 85662306a36Sopenharmony_ci int err; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci if (!inode || !igrab(inode)) 85962306a36Sopenharmony_ci goto out; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci err = dquot_quota_off(sb, type); 86262306a36Sopenharmony_ci if (err) 86362306a36Sopenharmony_ci goto out_put; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci inode_lock(inode); 86662306a36Sopenharmony_ci JFS_IP(inode)->mode2 &= ~(JFS_NOATIME_FL | JFS_IMMUTABLE_FL); 86762306a36Sopenharmony_ci inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE); 86862306a36Sopenharmony_ci inode_unlock(inode); 86962306a36Sopenharmony_ci mark_inode_dirty(inode); 87062306a36Sopenharmony_ciout_put: 87162306a36Sopenharmony_ci iput(inode); 87262306a36Sopenharmony_ci return err; 87362306a36Sopenharmony_ciout: 87462306a36Sopenharmony_ci return dquot_quota_off(sb, type); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci#endif 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cistatic const struct super_operations jfs_super_operations = { 87962306a36Sopenharmony_ci .alloc_inode = jfs_alloc_inode, 88062306a36Sopenharmony_ci .free_inode = jfs_free_inode, 88162306a36Sopenharmony_ci .dirty_inode = jfs_dirty_inode, 88262306a36Sopenharmony_ci .write_inode = jfs_write_inode, 88362306a36Sopenharmony_ci .evict_inode = jfs_evict_inode, 88462306a36Sopenharmony_ci .put_super = jfs_put_super, 88562306a36Sopenharmony_ci .sync_fs = jfs_sync_fs, 88662306a36Sopenharmony_ci .freeze_fs = jfs_freeze, 88762306a36Sopenharmony_ci .unfreeze_fs = jfs_unfreeze, 88862306a36Sopenharmony_ci .statfs = jfs_statfs, 88962306a36Sopenharmony_ci .remount_fs = jfs_remount, 89062306a36Sopenharmony_ci .show_options = jfs_show_options, 89162306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 89262306a36Sopenharmony_ci .quota_read = jfs_quota_read, 89362306a36Sopenharmony_ci .quota_write = jfs_quota_write, 89462306a36Sopenharmony_ci .get_dquots = jfs_get_dquots, 89562306a36Sopenharmony_ci#endif 89662306a36Sopenharmony_ci}; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic const struct export_operations jfs_export_operations = { 89962306a36Sopenharmony_ci .fh_to_dentry = jfs_fh_to_dentry, 90062306a36Sopenharmony_ci .fh_to_parent = jfs_fh_to_parent, 90162306a36Sopenharmony_ci .get_parent = jfs_get_parent, 90262306a36Sopenharmony_ci}; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cistatic struct file_system_type jfs_fs_type = { 90562306a36Sopenharmony_ci .owner = THIS_MODULE, 90662306a36Sopenharmony_ci .name = "jfs", 90762306a36Sopenharmony_ci .mount = jfs_do_mount, 90862306a36Sopenharmony_ci .kill_sb = kill_block_super, 90962306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 91062306a36Sopenharmony_ci}; 91162306a36Sopenharmony_ciMODULE_ALIAS_FS("jfs"); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic void init_once(void *foo) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci memset(jfs_ip, 0, sizeof(struct jfs_inode_info)); 91862306a36Sopenharmony_ci INIT_LIST_HEAD(&jfs_ip->anon_inode_list); 91962306a36Sopenharmony_ci init_rwsem(&jfs_ip->rdwrlock); 92062306a36Sopenharmony_ci mutex_init(&jfs_ip->commit_mutex); 92162306a36Sopenharmony_ci init_rwsem(&jfs_ip->xattr_sem); 92262306a36Sopenharmony_ci spin_lock_init(&jfs_ip->ag_lock); 92362306a36Sopenharmony_ci jfs_ip->active_ag = -1; 92462306a36Sopenharmony_ci inode_init_once(&jfs_ip->vfs_inode); 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic int __init init_jfs_fs(void) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci int i; 93062306a36Sopenharmony_ci int rc; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci jfs_inode_cachep = 93362306a36Sopenharmony_ci kmem_cache_create_usercopy("jfs_ip", sizeof(struct jfs_inode_info), 93462306a36Sopenharmony_ci 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT, 93562306a36Sopenharmony_ci offsetof(struct jfs_inode_info, i_inline_all), 93662306a36Sopenharmony_ci sizeof_field(struct jfs_inode_info, i_inline_all), 93762306a36Sopenharmony_ci init_once); 93862306a36Sopenharmony_ci if (jfs_inode_cachep == NULL) 93962306a36Sopenharmony_ci return -ENOMEM; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* 94262306a36Sopenharmony_ci * Metapage initialization 94362306a36Sopenharmony_ci */ 94462306a36Sopenharmony_ci rc = metapage_init(); 94562306a36Sopenharmony_ci if (rc) { 94662306a36Sopenharmony_ci jfs_err("metapage_init failed w/rc = %d", rc); 94762306a36Sopenharmony_ci goto free_slab; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci /* 95162306a36Sopenharmony_ci * Transaction Manager initialization 95262306a36Sopenharmony_ci */ 95362306a36Sopenharmony_ci rc = txInit(); 95462306a36Sopenharmony_ci if (rc) { 95562306a36Sopenharmony_ci jfs_err("txInit failed w/rc = %d", rc); 95662306a36Sopenharmony_ci goto free_metapage; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* 96062306a36Sopenharmony_ci * I/O completion thread (endio) 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO"); 96362306a36Sopenharmony_ci if (IS_ERR(jfsIOthread)) { 96462306a36Sopenharmony_ci rc = PTR_ERR(jfsIOthread); 96562306a36Sopenharmony_ci jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); 96662306a36Sopenharmony_ci goto end_txmngr; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (commit_threads < 1) 97062306a36Sopenharmony_ci commit_threads = num_online_cpus(); 97162306a36Sopenharmony_ci if (commit_threads > MAX_COMMIT_THREADS) 97262306a36Sopenharmony_ci commit_threads = MAX_COMMIT_THREADS; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci for (i = 0; i < commit_threads; i++) { 97562306a36Sopenharmony_ci jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL, 97662306a36Sopenharmony_ci "jfsCommit"); 97762306a36Sopenharmony_ci if (IS_ERR(jfsCommitThread[i])) { 97862306a36Sopenharmony_ci rc = PTR_ERR(jfsCommitThread[i]); 97962306a36Sopenharmony_ci jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); 98062306a36Sopenharmony_ci commit_threads = i; 98162306a36Sopenharmony_ci goto kill_committask; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci jfsSyncThread = kthread_run(jfs_sync, NULL, "jfsSync"); 98662306a36Sopenharmony_ci if (IS_ERR(jfsSyncThread)) { 98762306a36Sopenharmony_ci rc = PTR_ERR(jfsSyncThread); 98862306a36Sopenharmony_ci jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); 98962306a36Sopenharmony_ci goto kill_committask; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci#ifdef PROC_FS_JFS 99362306a36Sopenharmony_ci jfs_proc_init(); 99462306a36Sopenharmony_ci#endif 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci rc = register_filesystem(&jfs_fs_type); 99762306a36Sopenharmony_ci if (!rc) 99862306a36Sopenharmony_ci return 0; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci#ifdef PROC_FS_JFS 100162306a36Sopenharmony_ci jfs_proc_clean(); 100262306a36Sopenharmony_ci#endif 100362306a36Sopenharmony_ci kthread_stop(jfsSyncThread); 100462306a36Sopenharmony_cikill_committask: 100562306a36Sopenharmony_ci for (i = 0; i < commit_threads; i++) 100662306a36Sopenharmony_ci kthread_stop(jfsCommitThread[i]); 100762306a36Sopenharmony_ci kthread_stop(jfsIOthread); 100862306a36Sopenharmony_ciend_txmngr: 100962306a36Sopenharmony_ci txExit(); 101062306a36Sopenharmony_cifree_metapage: 101162306a36Sopenharmony_ci metapage_exit(); 101262306a36Sopenharmony_cifree_slab: 101362306a36Sopenharmony_ci kmem_cache_destroy(jfs_inode_cachep); 101462306a36Sopenharmony_ci return rc; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic void __exit exit_jfs_fs(void) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci int i; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci jfs_info("exit_jfs_fs called"); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci txExit(); 102462306a36Sopenharmony_ci metapage_exit(); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci kthread_stop(jfsIOthread); 102762306a36Sopenharmony_ci for (i = 0; i < commit_threads; i++) 102862306a36Sopenharmony_ci kthread_stop(jfsCommitThread[i]); 102962306a36Sopenharmony_ci kthread_stop(jfsSyncThread); 103062306a36Sopenharmony_ci#ifdef PROC_FS_JFS 103162306a36Sopenharmony_ci jfs_proc_clean(); 103262306a36Sopenharmony_ci#endif 103362306a36Sopenharmony_ci unregister_filesystem(&jfs_fs_type); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* 103662306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 103762306a36Sopenharmony_ci * destroy cache. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ci rcu_barrier(); 104062306a36Sopenharmony_ci kmem_cache_destroy(jfs_inode_cachep); 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cimodule_init(init_jfs_fs) 104462306a36Sopenharmony_cimodule_exit(exit_jfs_fs) 1045