162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ufs/super.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1998 662306a36Sopenharmony_ci * Daniel Pirkl <daniel.pirkl@email.cz> 762306a36Sopenharmony_ci * Charles University, Faculty of Mathematics and Physics 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* Derived from 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * linux/fs/ext2/super.c 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 1562306a36Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 1662306a36Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal 1762306a36Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * from 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * linux/fs/minix/inode.c 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Big-endian to little-endian byte-swapping/bitmaps by 2662306a36Sopenharmony_ci * David S. Miller (davem@caip.rutgers.edu), 1995 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * Inspired by 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * linux/fs/ufs/super.c 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * Copyright (C) 1996 3562306a36Sopenharmony_ci * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) 3662306a36Sopenharmony_ci * Laboratory for Computer Science Research Computing Facility 3762306a36Sopenharmony_ci * Rutgers, The State University of New Jersey 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Kernel module support added on 96/04/26 by 4262306a36Sopenharmony_ci * Stefan Reinauer <stepan@home.culture.mipt.ru> 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * Module usage counts added on 96/04/29 by 4562306a36Sopenharmony_ci * Gertjan van Wingerde <gwingerde@gmail.com> 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Clean swab support on 19970406 by 4862306a36Sopenharmony_ci * Francois-Rene Rideau <fare@tunes.org> 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * 4.4BSD (FreeBSD) support added on February 1st 1998 by 5162306a36Sopenharmony_ci * Niels Kristian Bech Jensen <nkbj@image.dk> partially based 5262306a36Sopenharmony_ci * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * NeXTstep support added on February 5th 1998 by 5562306a36Sopenharmony_ci * Niels Kristian Bech Jensen <nkbj@image.dk>. 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * write support Daniel Pirkl <daniel.pirkl@email.cz> 1998 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * HP/UX hfs filesystem support added by 6062306a36Sopenharmony_ci * Martin K. Petersen <mkp@mkp.net>, August 1999 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * UFS2 (of FreeBSD 5.x) support added by 6362306a36Sopenharmony_ci * Niraj Kumar <niraj17@iitbombay.org>, Jan 2004 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * UFS2 write support added by 6662306a36Sopenharmony_ci * Evgeniy Dushistov <dushistov@mail.ru>, 2007 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#include <linux/exportfs.h> 7062306a36Sopenharmony_ci#include <linux/module.h> 7162306a36Sopenharmony_ci#include <linux/bitops.h> 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#include <linux/stdarg.h> 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#include <linux/uaccess.h> 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#include <linux/errno.h> 7862306a36Sopenharmony_ci#include <linux/fs.h> 7962306a36Sopenharmony_ci#include <linux/slab.h> 8062306a36Sopenharmony_ci#include <linux/time.h> 8162306a36Sopenharmony_ci#include <linux/stat.h> 8262306a36Sopenharmony_ci#include <linux/string.h> 8362306a36Sopenharmony_ci#include <linux/blkdev.h> 8462306a36Sopenharmony_ci#include <linux/backing-dev.h> 8562306a36Sopenharmony_ci#include <linux/init.h> 8662306a36Sopenharmony_ci#include <linux/parser.h> 8762306a36Sopenharmony_ci#include <linux/buffer_head.h> 8862306a36Sopenharmony_ci#include <linux/vfs.h> 8962306a36Sopenharmony_ci#include <linux/log2.h> 9062306a36Sopenharmony_ci#include <linux/mount.h> 9162306a36Sopenharmony_ci#include <linux/seq_file.h> 9262306a36Sopenharmony_ci#include <linux/iversion.h> 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#include "ufs_fs.h" 9562306a36Sopenharmony_ci#include "ufs.h" 9662306a36Sopenharmony_ci#include "swab.h" 9762306a36Sopenharmony_ci#include "util.h" 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic struct inode *ufs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 10262306a36Sopenharmony_ci struct inode *inode; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (ino < UFS_ROOTINO || ino > (u64)uspi->s_ncg * uspi->s_ipg) 10562306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci inode = ufs_iget(sb, ino); 10862306a36Sopenharmony_ci if (IS_ERR(inode)) 10962306a36Sopenharmony_ci return ERR_CAST(inode); 11062306a36Sopenharmony_ci if (generation && inode->i_generation != generation) { 11162306a36Sopenharmony_ci iput(inode); 11262306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci return inode; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic struct dentry *ufs_fh_to_dentry(struct super_block *sb, struct fid *fid, 11862306a36Sopenharmony_ci int fh_len, int fh_type) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci return generic_fh_to_dentry(sb, fid, fh_len, fh_type, ufs_nfs_get_inode); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic struct dentry *ufs_fh_to_parent(struct super_block *sb, struct fid *fid, 12462306a36Sopenharmony_ci int fh_len, int fh_type) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci return generic_fh_to_parent(sb, fid, fh_len, fh_type, ufs_nfs_get_inode); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic struct dentry *ufs_get_parent(struct dentry *child) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci ino_t ino; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ino = ufs_inode_by_name(d_inode(child), &dotdot_name); 13462306a36Sopenharmony_ci if (!ino) 13562306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 13662306a36Sopenharmony_ci return d_obtain_alias(ufs_iget(child->d_sb, ino)); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic const struct export_operations ufs_export_ops = { 14062306a36Sopenharmony_ci .fh_to_dentry = ufs_fh_to_dentry, 14162306a36Sopenharmony_ci .fh_to_parent = ufs_fh_to_parent, 14262306a36Sopenharmony_ci .get_parent = ufs_get_parent, 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#ifdef CONFIG_UFS_DEBUG 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * Print contents of ufs_super_block, useful for debugging 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_cistatic void ufs_print_super_stuff(struct super_block *sb, 15062306a36Sopenharmony_ci struct ufs_super_block_first *usb1, 15162306a36Sopenharmony_ci struct ufs_super_block_second *usb2, 15262306a36Sopenharmony_ci struct ufs_super_block_third *usb3) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci u32 magic = fs32_to_cpu(sb, usb3->fs_magic); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci pr_debug("ufs_print_super_stuff\n"); 15762306a36Sopenharmony_ci pr_debug(" magic: 0x%x\n", magic); 15862306a36Sopenharmony_ci if (fs32_to_cpu(sb, usb3->fs_magic) == UFS2_MAGIC) { 15962306a36Sopenharmony_ci pr_debug(" fs_size: %llu\n", (unsigned long long) 16062306a36Sopenharmony_ci fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size)); 16162306a36Sopenharmony_ci pr_debug(" fs_dsize: %llu\n", (unsigned long long) 16262306a36Sopenharmony_ci fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize)); 16362306a36Sopenharmony_ci pr_debug(" bsize: %u\n", 16462306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_bsize)); 16562306a36Sopenharmony_ci pr_debug(" fsize: %u\n", 16662306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_fsize)); 16762306a36Sopenharmony_ci pr_debug(" fs_volname: %s\n", usb2->fs_un.fs_u2.fs_volname); 16862306a36Sopenharmony_ci pr_debug(" fs_sblockloc: %llu\n", (unsigned long long) 16962306a36Sopenharmony_ci fs64_to_cpu(sb, usb2->fs_un.fs_u2.fs_sblockloc)); 17062306a36Sopenharmony_ci pr_debug(" cs_ndir(No of dirs): %llu\n", (unsigned long long) 17162306a36Sopenharmony_ci fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir)); 17262306a36Sopenharmony_ci pr_debug(" cs_nbfree(No of free blocks): %llu\n", 17362306a36Sopenharmony_ci (unsigned long long) 17462306a36Sopenharmony_ci fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree)); 17562306a36Sopenharmony_ci pr_info(" cs_nifree(Num of free inodes): %llu\n", 17662306a36Sopenharmony_ci (unsigned long long) 17762306a36Sopenharmony_ci fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nifree)); 17862306a36Sopenharmony_ci pr_info(" cs_nffree(Num of free frags): %llu\n", 17962306a36Sopenharmony_ci (unsigned long long) 18062306a36Sopenharmony_ci fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nffree)); 18162306a36Sopenharmony_ci pr_info(" fs_maxsymlinklen: %u\n", 18262306a36Sopenharmony_ci fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen)); 18362306a36Sopenharmony_ci } else { 18462306a36Sopenharmony_ci pr_debug(" sblkno: %u\n", fs32_to_cpu(sb, usb1->fs_sblkno)); 18562306a36Sopenharmony_ci pr_debug(" cblkno: %u\n", fs32_to_cpu(sb, usb1->fs_cblkno)); 18662306a36Sopenharmony_ci pr_debug(" iblkno: %u\n", fs32_to_cpu(sb, usb1->fs_iblkno)); 18762306a36Sopenharmony_ci pr_debug(" dblkno: %u\n", fs32_to_cpu(sb, usb1->fs_dblkno)); 18862306a36Sopenharmony_ci pr_debug(" cgoffset: %u\n", 18962306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_cgoffset)); 19062306a36Sopenharmony_ci pr_debug(" ~cgmask: 0x%x\n", 19162306a36Sopenharmony_ci ~fs32_to_cpu(sb, usb1->fs_cgmask)); 19262306a36Sopenharmony_ci pr_debug(" size: %u\n", fs32_to_cpu(sb, usb1->fs_size)); 19362306a36Sopenharmony_ci pr_debug(" dsize: %u\n", fs32_to_cpu(sb, usb1->fs_dsize)); 19462306a36Sopenharmony_ci pr_debug(" ncg: %u\n", fs32_to_cpu(sb, usb1->fs_ncg)); 19562306a36Sopenharmony_ci pr_debug(" bsize: %u\n", fs32_to_cpu(sb, usb1->fs_bsize)); 19662306a36Sopenharmony_ci pr_debug(" fsize: %u\n", fs32_to_cpu(sb, usb1->fs_fsize)); 19762306a36Sopenharmony_ci pr_debug(" frag: %u\n", fs32_to_cpu(sb, usb1->fs_frag)); 19862306a36Sopenharmony_ci pr_debug(" fragshift: %u\n", 19962306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_fragshift)); 20062306a36Sopenharmony_ci pr_debug(" ~fmask: %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask)); 20162306a36Sopenharmony_ci pr_debug(" fshift: %u\n", fs32_to_cpu(sb, usb1->fs_fshift)); 20262306a36Sopenharmony_ci pr_debug(" sbsize: %u\n", fs32_to_cpu(sb, usb1->fs_sbsize)); 20362306a36Sopenharmony_ci pr_debug(" spc: %u\n", fs32_to_cpu(sb, usb1->fs_spc)); 20462306a36Sopenharmony_ci pr_debug(" cpg: %u\n", fs32_to_cpu(sb, usb1->fs_cpg)); 20562306a36Sopenharmony_ci pr_debug(" ipg: %u\n", fs32_to_cpu(sb, usb1->fs_ipg)); 20662306a36Sopenharmony_ci pr_debug(" fpg: %u\n", fs32_to_cpu(sb, usb1->fs_fpg)); 20762306a36Sopenharmony_ci pr_debug(" csaddr: %u\n", fs32_to_cpu(sb, usb1->fs_csaddr)); 20862306a36Sopenharmony_ci pr_debug(" cssize: %u\n", fs32_to_cpu(sb, usb1->fs_cssize)); 20962306a36Sopenharmony_ci pr_debug(" cgsize: %u\n", fs32_to_cpu(sb, usb1->fs_cgsize)); 21062306a36Sopenharmony_ci pr_debug(" fstodb: %u\n", 21162306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_fsbtodb)); 21262306a36Sopenharmony_ci pr_debug(" nrpos: %u\n", fs32_to_cpu(sb, usb3->fs_nrpos)); 21362306a36Sopenharmony_ci pr_debug(" ndir %u\n", 21462306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir)); 21562306a36Sopenharmony_ci pr_debug(" nifree %u\n", 21662306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree)); 21762306a36Sopenharmony_ci pr_debug(" nbfree %u\n", 21862306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)); 21962306a36Sopenharmony_ci pr_debug(" nffree %u\n", 22062306a36Sopenharmony_ci fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree)); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci pr_debug("\n"); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* 22662306a36Sopenharmony_ci * Print contents of ufs_cylinder_group, useful for debugging 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_cistatic void ufs_print_cylinder_stuff(struct super_block *sb, 22962306a36Sopenharmony_ci struct ufs_cylinder_group *cg) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci pr_debug("\nufs_print_cylinder_stuff\n"); 23262306a36Sopenharmony_ci pr_debug("size of ucg: %zu\n", sizeof(struct ufs_cylinder_group)); 23362306a36Sopenharmony_ci pr_debug(" magic: %x\n", fs32_to_cpu(sb, cg->cg_magic)); 23462306a36Sopenharmony_ci pr_debug(" time: %u\n", fs32_to_cpu(sb, cg->cg_time)); 23562306a36Sopenharmony_ci pr_debug(" cgx: %u\n", fs32_to_cpu(sb, cg->cg_cgx)); 23662306a36Sopenharmony_ci pr_debug(" ncyl: %u\n", fs16_to_cpu(sb, cg->cg_ncyl)); 23762306a36Sopenharmony_ci pr_debug(" niblk: %u\n", fs16_to_cpu(sb, cg->cg_niblk)); 23862306a36Sopenharmony_ci pr_debug(" ndblk: %u\n", fs32_to_cpu(sb, cg->cg_ndblk)); 23962306a36Sopenharmony_ci pr_debug(" cs_ndir: %u\n", fs32_to_cpu(sb, cg->cg_cs.cs_ndir)); 24062306a36Sopenharmony_ci pr_debug(" cs_nbfree: %u\n", fs32_to_cpu(sb, cg->cg_cs.cs_nbfree)); 24162306a36Sopenharmony_ci pr_debug(" cs_nifree: %u\n", fs32_to_cpu(sb, cg->cg_cs.cs_nifree)); 24262306a36Sopenharmony_ci pr_debug(" cs_nffree: %u\n", fs32_to_cpu(sb, cg->cg_cs.cs_nffree)); 24362306a36Sopenharmony_ci pr_debug(" rotor: %u\n", fs32_to_cpu(sb, cg->cg_rotor)); 24462306a36Sopenharmony_ci pr_debug(" frotor: %u\n", fs32_to_cpu(sb, cg->cg_frotor)); 24562306a36Sopenharmony_ci pr_debug(" irotor: %u\n", fs32_to_cpu(sb, cg->cg_irotor)); 24662306a36Sopenharmony_ci pr_debug(" frsum: %u, %u, %u, %u, %u, %u, %u, %u\n", 24762306a36Sopenharmony_ci fs32_to_cpu(sb, cg->cg_frsum[0]), fs32_to_cpu(sb, cg->cg_frsum[1]), 24862306a36Sopenharmony_ci fs32_to_cpu(sb, cg->cg_frsum[2]), fs32_to_cpu(sb, cg->cg_frsum[3]), 24962306a36Sopenharmony_ci fs32_to_cpu(sb, cg->cg_frsum[4]), fs32_to_cpu(sb, cg->cg_frsum[5]), 25062306a36Sopenharmony_ci fs32_to_cpu(sb, cg->cg_frsum[6]), fs32_to_cpu(sb, cg->cg_frsum[7])); 25162306a36Sopenharmony_ci pr_debug(" btotoff: %u\n", fs32_to_cpu(sb, cg->cg_btotoff)); 25262306a36Sopenharmony_ci pr_debug(" boff: %u\n", fs32_to_cpu(sb, cg->cg_boff)); 25362306a36Sopenharmony_ci pr_debug(" iuseoff: %u\n", fs32_to_cpu(sb, cg->cg_iusedoff)); 25462306a36Sopenharmony_ci pr_debug(" freeoff: %u\n", fs32_to_cpu(sb, cg->cg_freeoff)); 25562306a36Sopenharmony_ci pr_debug(" nextfreeoff: %u\n", fs32_to_cpu(sb, cg->cg_nextfreeoff)); 25662306a36Sopenharmony_ci pr_debug(" clustersumoff %u\n", 25762306a36Sopenharmony_ci fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff)); 25862306a36Sopenharmony_ci pr_debug(" clusteroff %u\n", 25962306a36Sopenharmony_ci fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff)); 26062306a36Sopenharmony_ci pr_debug(" nclusterblks %u\n", 26162306a36Sopenharmony_ci fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks)); 26262306a36Sopenharmony_ci pr_debug("\n"); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci#else 26562306a36Sopenharmony_ci# define ufs_print_super_stuff(sb, usb1, usb2, usb3) /**/ 26662306a36Sopenharmony_ci# define ufs_print_cylinder_stuff(sb, cg) /**/ 26762306a36Sopenharmony_ci#endif /* CONFIG_UFS_DEBUG */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic const struct super_operations ufs_super_ops; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_civoid ufs_error (struct super_block * sb, const char * function, 27262306a36Sopenharmony_ci const char * fmt, ...) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 27562306a36Sopenharmony_ci struct ufs_super_block_first * usb1; 27662306a36Sopenharmony_ci struct va_format vaf; 27762306a36Sopenharmony_ci va_list args; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci uspi = UFS_SB(sb)->s_uspi; 28062306a36Sopenharmony_ci usb1 = ubh_get_usb_first(uspi); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 28362306a36Sopenharmony_ci usb1->fs_clean = UFS_FSBAD; 28462306a36Sopenharmony_ci ubh_mark_buffer_dirty(USPI_UBH(uspi)); 28562306a36Sopenharmony_ci ufs_mark_sb_dirty(sb); 28662306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci va_start(args, fmt); 28962306a36Sopenharmony_ci vaf.fmt = fmt; 29062306a36Sopenharmony_ci vaf.va = &args; 29162306a36Sopenharmony_ci switch (UFS_SB(sb)->s_mount_opt & UFS_MOUNT_ONERROR) { 29262306a36Sopenharmony_ci case UFS_MOUNT_ONERROR_PANIC: 29362306a36Sopenharmony_ci panic("panic (device %s): %s: %pV\n", 29462306a36Sopenharmony_ci sb->s_id, function, &vaf); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci case UFS_MOUNT_ONERROR_LOCK: 29762306a36Sopenharmony_ci case UFS_MOUNT_ONERROR_UMOUNT: 29862306a36Sopenharmony_ci case UFS_MOUNT_ONERROR_REPAIR: 29962306a36Sopenharmony_ci pr_crit("error (device %s): %s: %pV\n", 30062306a36Sopenharmony_ci sb->s_id, function, &vaf); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci va_end(args); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_civoid ufs_panic (struct super_block * sb, const char * function, 30662306a36Sopenharmony_ci const char * fmt, ...) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 30962306a36Sopenharmony_ci struct ufs_super_block_first * usb1; 31062306a36Sopenharmony_ci struct va_format vaf; 31162306a36Sopenharmony_ci va_list args; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci uspi = UFS_SB(sb)->s_uspi; 31462306a36Sopenharmony_ci usb1 = ubh_get_usb_first(uspi); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 31762306a36Sopenharmony_ci usb1->fs_clean = UFS_FSBAD; 31862306a36Sopenharmony_ci ubh_mark_buffer_dirty(USPI_UBH(uspi)); 31962306a36Sopenharmony_ci ufs_mark_sb_dirty(sb); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci va_start(args, fmt); 32262306a36Sopenharmony_ci vaf.fmt = fmt; 32362306a36Sopenharmony_ci vaf.va = &args; 32462306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 32562306a36Sopenharmony_ci pr_crit("panic (device %s): %s: %pV\n", 32662306a36Sopenharmony_ci sb->s_id, function, &vaf); 32762306a36Sopenharmony_ci va_end(args); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_civoid ufs_warning (struct super_block * sb, const char * function, 33162306a36Sopenharmony_ci const char * fmt, ...) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct va_format vaf; 33462306a36Sopenharmony_ci va_list args; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci va_start(args, fmt); 33762306a36Sopenharmony_ci vaf.fmt = fmt; 33862306a36Sopenharmony_ci vaf.va = &args; 33962306a36Sopenharmony_ci pr_warn("(device %s): %s: %pV\n", 34062306a36Sopenharmony_ci sb->s_id, function, &vaf); 34162306a36Sopenharmony_ci va_end(args); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cienum { 34562306a36Sopenharmony_ci Opt_type_old = UFS_MOUNT_UFSTYPE_OLD, 34662306a36Sopenharmony_ci Opt_type_sunx86 = UFS_MOUNT_UFSTYPE_SUNx86, 34762306a36Sopenharmony_ci Opt_type_sun = UFS_MOUNT_UFSTYPE_SUN, 34862306a36Sopenharmony_ci Opt_type_sunos = UFS_MOUNT_UFSTYPE_SUNOS, 34962306a36Sopenharmony_ci Opt_type_44bsd = UFS_MOUNT_UFSTYPE_44BSD, 35062306a36Sopenharmony_ci Opt_type_ufs2 = UFS_MOUNT_UFSTYPE_UFS2, 35162306a36Sopenharmony_ci Opt_type_hp = UFS_MOUNT_UFSTYPE_HP, 35262306a36Sopenharmony_ci Opt_type_nextstepcd = UFS_MOUNT_UFSTYPE_NEXTSTEP_CD, 35362306a36Sopenharmony_ci Opt_type_nextstep = UFS_MOUNT_UFSTYPE_NEXTSTEP, 35462306a36Sopenharmony_ci Opt_type_openstep = UFS_MOUNT_UFSTYPE_OPENSTEP, 35562306a36Sopenharmony_ci Opt_onerror_panic = UFS_MOUNT_ONERROR_PANIC, 35662306a36Sopenharmony_ci Opt_onerror_lock = UFS_MOUNT_ONERROR_LOCK, 35762306a36Sopenharmony_ci Opt_onerror_umount = UFS_MOUNT_ONERROR_UMOUNT, 35862306a36Sopenharmony_ci Opt_onerror_repair = UFS_MOUNT_ONERROR_REPAIR, 35962306a36Sopenharmony_ci Opt_err 36062306a36Sopenharmony_ci}; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic const match_table_t tokens = { 36362306a36Sopenharmony_ci {Opt_type_old, "ufstype=old"}, 36462306a36Sopenharmony_ci {Opt_type_sunx86, "ufstype=sunx86"}, 36562306a36Sopenharmony_ci {Opt_type_sun, "ufstype=sun"}, 36662306a36Sopenharmony_ci {Opt_type_sunos, "ufstype=sunos"}, 36762306a36Sopenharmony_ci {Opt_type_44bsd, "ufstype=44bsd"}, 36862306a36Sopenharmony_ci {Opt_type_ufs2, "ufstype=ufs2"}, 36962306a36Sopenharmony_ci {Opt_type_ufs2, "ufstype=5xbsd"}, 37062306a36Sopenharmony_ci {Opt_type_hp, "ufstype=hp"}, 37162306a36Sopenharmony_ci {Opt_type_nextstepcd, "ufstype=nextstep-cd"}, 37262306a36Sopenharmony_ci {Opt_type_nextstep, "ufstype=nextstep"}, 37362306a36Sopenharmony_ci {Opt_type_openstep, "ufstype=openstep"}, 37462306a36Sopenharmony_ci/*end of possible ufs types */ 37562306a36Sopenharmony_ci {Opt_onerror_panic, "onerror=panic"}, 37662306a36Sopenharmony_ci {Opt_onerror_lock, "onerror=lock"}, 37762306a36Sopenharmony_ci {Opt_onerror_umount, "onerror=umount"}, 37862306a36Sopenharmony_ci {Opt_onerror_repair, "onerror=repair"}, 37962306a36Sopenharmony_ci {Opt_err, NULL} 38062306a36Sopenharmony_ci}; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int ufs_parse_options (char * options, unsigned * mount_options) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci char * p; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci UFSD("ENTER\n"); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (!options) 38962306a36Sopenharmony_ci return 1; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 39262306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 39362306a36Sopenharmony_ci int token; 39462306a36Sopenharmony_ci if (!*p) 39562306a36Sopenharmony_ci continue; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci token = match_token(p, tokens, args); 39862306a36Sopenharmony_ci switch (token) { 39962306a36Sopenharmony_ci case Opt_type_old: 40062306a36Sopenharmony_ci ufs_clear_opt (*mount_options, UFSTYPE); 40162306a36Sopenharmony_ci ufs_set_opt (*mount_options, UFSTYPE_OLD); 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci case Opt_type_sunx86: 40462306a36Sopenharmony_ci ufs_clear_opt (*mount_options, UFSTYPE); 40562306a36Sopenharmony_ci ufs_set_opt (*mount_options, UFSTYPE_SUNx86); 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci case Opt_type_sun: 40862306a36Sopenharmony_ci ufs_clear_opt (*mount_options, UFSTYPE); 40962306a36Sopenharmony_ci ufs_set_opt (*mount_options, UFSTYPE_SUN); 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci case Opt_type_sunos: 41262306a36Sopenharmony_ci ufs_clear_opt(*mount_options, UFSTYPE); 41362306a36Sopenharmony_ci ufs_set_opt(*mount_options, UFSTYPE_SUNOS); 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci case Opt_type_44bsd: 41662306a36Sopenharmony_ci ufs_clear_opt (*mount_options, UFSTYPE); 41762306a36Sopenharmony_ci ufs_set_opt (*mount_options, UFSTYPE_44BSD); 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci case Opt_type_ufs2: 42062306a36Sopenharmony_ci ufs_clear_opt(*mount_options, UFSTYPE); 42162306a36Sopenharmony_ci ufs_set_opt(*mount_options, UFSTYPE_UFS2); 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci case Opt_type_hp: 42462306a36Sopenharmony_ci ufs_clear_opt (*mount_options, UFSTYPE); 42562306a36Sopenharmony_ci ufs_set_opt (*mount_options, UFSTYPE_HP); 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci case Opt_type_nextstepcd: 42862306a36Sopenharmony_ci ufs_clear_opt (*mount_options, UFSTYPE); 42962306a36Sopenharmony_ci ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD); 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case Opt_type_nextstep: 43262306a36Sopenharmony_ci ufs_clear_opt (*mount_options, UFSTYPE); 43362306a36Sopenharmony_ci ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP); 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci case Opt_type_openstep: 43662306a36Sopenharmony_ci ufs_clear_opt (*mount_options, UFSTYPE); 43762306a36Sopenharmony_ci ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP); 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci case Opt_onerror_panic: 44062306a36Sopenharmony_ci ufs_clear_opt (*mount_options, ONERROR); 44162306a36Sopenharmony_ci ufs_set_opt (*mount_options, ONERROR_PANIC); 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci case Opt_onerror_lock: 44462306a36Sopenharmony_ci ufs_clear_opt (*mount_options, ONERROR); 44562306a36Sopenharmony_ci ufs_set_opt (*mount_options, ONERROR_LOCK); 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci case Opt_onerror_umount: 44862306a36Sopenharmony_ci ufs_clear_opt (*mount_options, ONERROR); 44962306a36Sopenharmony_ci ufs_set_opt (*mount_options, ONERROR_UMOUNT); 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci case Opt_onerror_repair: 45262306a36Sopenharmony_ci pr_err("Unable to do repair on error, will lock lock instead\n"); 45362306a36Sopenharmony_ci ufs_clear_opt (*mount_options, ONERROR); 45462306a36Sopenharmony_ci ufs_set_opt (*mount_options, ONERROR_REPAIR); 45562306a36Sopenharmony_ci break; 45662306a36Sopenharmony_ci default: 45762306a36Sopenharmony_ci pr_err("Invalid option: \"%s\" or missing value\n", p); 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci return 1; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci/* 46562306a36Sopenharmony_ci * Different types of UFS hold fs_cstotal in different 46662306a36Sopenharmony_ci * places, and use different data structure for it. 46762306a36Sopenharmony_ci * To make things simpler we just copy fs_cstotal to ufs_sb_private_info 46862306a36Sopenharmony_ci */ 46962306a36Sopenharmony_cistatic void ufs_setup_cstotal(struct super_block *sb) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct ufs_sb_info *sbi = UFS_SB(sb); 47262306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = sbi->s_uspi; 47362306a36Sopenharmony_ci struct ufs_super_block_first *usb1; 47462306a36Sopenharmony_ci struct ufs_super_block_second *usb2; 47562306a36Sopenharmony_ci struct ufs_super_block_third *usb3; 47662306a36Sopenharmony_ci unsigned mtype = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci UFSD("ENTER, mtype=%u\n", mtype); 47962306a36Sopenharmony_ci usb1 = ubh_get_usb_first(uspi); 48062306a36Sopenharmony_ci usb2 = ubh_get_usb_second(uspi); 48162306a36Sopenharmony_ci usb3 = ubh_get_usb_third(uspi); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if ((mtype == UFS_MOUNT_UFSTYPE_44BSD && 48462306a36Sopenharmony_ci (usb2->fs_un.fs_u2.fs_maxbsize == usb1->fs_bsize)) || 48562306a36Sopenharmony_ci mtype == UFS_MOUNT_UFSTYPE_UFS2) { 48662306a36Sopenharmony_ci /*we have statistic in different place, then usual*/ 48762306a36Sopenharmony_ci uspi->cs_total.cs_ndir = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir); 48862306a36Sopenharmony_ci uspi->cs_total.cs_nbfree = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree); 48962306a36Sopenharmony_ci uspi->cs_total.cs_nifree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nifree); 49062306a36Sopenharmony_ci uspi->cs_total.cs_nffree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nffree); 49162306a36Sopenharmony_ci } else { 49262306a36Sopenharmony_ci uspi->cs_total.cs_ndir = fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir); 49362306a36Sopenharmony_ci uspi->cs_total.cs_nbfree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree); 49462306a36Sopenharmony_ci uspi->cs_total.cs_nifree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree); 49562306a36Sopenharmony_ci uspi->cs_total.cs_nffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci UFSD("EXIT\n"); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/* 50162306a36Sopenharmony_ci * Read on-disk structures associated with cylinder groups 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_cistatic int ufs_read_cylinder_structures(struct super_block *sb) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct ufs_sb_info *sbi = UFS_SB(sb); 50662306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = sbi->s_uspi; 50762306a36Sopenharmony_ci struct ufs_buffer_head * ubh; 50862306a36Sopenharmony_ci unsigned char * base, * space; 50962306a36Sopenharmony_ci unsigned size, blks, i; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci UFSD("ENTER\n"); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* 51462306a36Sopenharmony_ci * Read cs structures from (usually) first data block 51562306a36Sopenharmony_ci * on the device. 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci size = uspi->s_cssize; 51862306a36Sopenharmony_ci blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; 51962306a36Sopenharmony_ci base = space = kmalloc(size, GFP_NOFS); 52062306a36Sopenharmony_ci if (!base) 52162306a36Sopenharmony_ci goto failed; 52262306a36Sopenharmony_ci sbi->s_csp = (struct ufs_csum *)space; 52362306a36Sopenharmony_ci for (i = 0; i < blks; i += uspi->s_fpb) { 52462306a36Sopenharmony_ci size = uspi->s_bsize; 52562306a36Sopenharmony_ci if (i + uspi->s_fpb > blks) 52662306a36Sopenharmony_ci size = (blks - i) * uspi->s_fsize; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ubh = ubh_bread(sb, uspi->s_csaddr + i, size); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (!ubh) 53162306a36Sopenharmony_ci goto failed; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci ubh_ubhcpymem (space, ubh, size); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci space += size; 53662306a36Sopenharmony_ci ubh_brelse (ubh); 53762306a36Sopenharmony_ci ubh = NULL; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* 54162306a36Sopenharmony_ci * Read cylinder group (we read only first fragment from block 54262306a36Sopenharmony_ci * at this time) and prepare internal data structures for cg caching. 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_ci sbi->s_ucg = kmalloc_array(uspi->s_ncg, sizeof(struct buffer_head *), 54562306a36Sopenharmony_ci GFP_NOFS); 54662306a36Sopenharmony_ci if (!sbi->s_ucg) 54762306a36Sopenharmony_ci goto failed; 54862306a36Sopenharmony_ci for (i = 0; i < uspi->s_ncg; i++) 54962306a36Sopenharmony_ci sbi->s_ucg[i] = NULL; 55062306a36Sopenharmony_ci for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { 55162306a36Sopenharmony_ci sbi->s_ucpi[i] = NULL; 55262306a36Sopenharmony_ci sbi->s_cgno[i] = UFS_CGNO_EMPTY; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci for (i = 0; i < uspi->s_ncg; i++) { 55562306a36Sopenharmony_ci UFSD("read cg %u\n", i); 55662306a36Sopenharmony_ci if (!(sbi->s_ucg[i] = sb_bread(sb, ufs_cgcmin(i)))) 55762306a36Sopenharmony_ci goto failed; 55862306a36Sopenharmony_ci if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data)) 55962306a36Sopenharmony_ci goto failed; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { 56462306a36Sopenharmony_ci if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_NOFS))) 56562306a36Sopenharmony_ci goto failed; 56662306a36Sopenharmony_ci sbi->s_cgno[i] = UFS_CGNO_EMPTY; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci sbi->s_cg_loaded = 0; 56962306a36Sopenharmony_ci UFSD("EXIT\n"); 57062306a36Sopenharmony_ci return 1; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cifailed: 57362306a36Sopenharmony_ci kfree (base); 57462306a36Sopenharmony_ci if (sbi->s_ucg) { 57562306a36Sopenharmony_ci for (i = 0; i < uspi->s_ncg; i++) 57662306a36Sopenharmony_ci if (sbi->s_ucg[i]) 57762306a36Sopenharmony_ci brelse (sbi->s_ucg[i]); 57862306a36Sopenharmony_ci kfree (sbi->s_ucg); 57962306a36Sopenharmony_ci for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) 58062306a36Sopenharmony_ci kfree (sbi->s_ucpi[i]); 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci UFSD("EXIT (FAILED)\n"); 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/* 58762306a36Sopenharmony_ci * Sync our internal copy of fs_cstotal with disk 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_cistatic void ufs_put_cstotal(struct super_block *sb) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci unsigned mtype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE; 59262306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 59362306a36Sopenharmony_ci struct ufs_super_block_first *usb1; 59462306a36Sopenharmony_ci struct ufs_super_block_second *usb2; 59562306a36Sopenharmony_ci struct ufs_super_block_third *usb3; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci UFSD("ENTER\n"); 59862306a36Sopenharmony_ci usb1 = ubh_get_usb_first(uspi); 59962306a36Sopenharmony_ci usb2 = ubh_get_usb_second(uspi); 60062306a36Sopenharmony_ci usb3 = ubh_get_usb_third(uspi); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (mtype == UFS_MOUNT_UFSTYPE_UFS2) { 60362306a36Sopenharmony_ci /*we have statistic in different place, then usual*/ 60462306a36Sopenharmony_ci usb2->fs_un.fs_u2.cs_ndir = 60562306a36Sopenharmony_ci cpu_to_fs64(sb, uspi->cs_total.cs_ndir); 60662306a36Sopenharmony_ci usb2->fs_un.fs_u2.cs_nbfree = 60762306a36Sopenharmony_ci cpu_to_fs64(sb, uspi->cs_total.cs_nbfree); 60862306a36Sopenharmony_ci usb3->fs_un1.fs_u2.cs_nifree = 60962306a36Sopenharmony_ci cpu_to_fs64(sb, uspi->cs_total.cs_nifree); 61062306a36Sopenharmony_ci usb3->fs_un1.fs_u2.cs_nffree = 61162306a36Sopenharmony_ci cpu_to_fs64(sb, uspi->cs_total.cs_nffree); 61262306a36Sopenharmony_ci goto out; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (mtype == UFS_MOUNT_UFSTYPE_44BSD && 61662306a36Sopenharmony_ci (usb2->fs_un.fs_u2.fs_maxbsize == usb1->fs_bsize)) { 61762306a36Sopenharmony_ci /* store stats in both old and new places */ 61862306a36Sopenharmony_ci usb2->fs_un.fs_u2.cs_ndir = 61962306a36Sopenharmony_ci cpu_to_fs64(sb, uspi->cs_total.cs_ndir); 62062306a36Sopenharmony_ci usb2->fs_un.fs_u2.cs_nbfree = 62162306a36Sopenharmony_ci cpu_to_fs64(sb, uspi->cs_total.cs_nbfree); 62262306a36Sopenharmony_ci usb3->fs_un1.fs_u2.cs_nifree = 62362306a36Sopenharmony_ci cpu_to_fs64(sb, uspi->cs_total.cs_nifree); 62462306a36Sopenharmony_ci usb3->fs_un1.fs_u2.cs_nffree = 62562306a36Sopenharmony_ci cpu_to_fs64(sb, uspi->cs_total.cs_nffree); 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci usb1->fs_cstotal.cs_ndir = cpu_to_fs32(sb, uspi->cs_total.cs_ndir); 62862306a36Sopenharmony_ci usb1->fs_cstotal.cs_nbfree = cpu_to_fs32(sb, uspi->cs_total.cs_nbfree); 62962306a36Sopenharmony_ci usb1->fs_cstotal.cs_nifree = cpu_to_fs32(sb, uspi->cs_total.cs_nifree); 63062306a36Sopenharmony_ci usb1->fs_cstotal.cs_nffree = cpu_to_fs32(sb, uspi->cs_total.cs_nffree); 63162306a36Sopenharmony_ciout: 63262306a36Sopenharmony_ci ubh_mark_buffer_dirty(USPI_UBH(uspi)); 63362306a36Sopenharmony_ci ufs_print_super_stuff(sb, usb1, usb2, usb3); 63462306a36Sopenharmony_ci UFSD("EXIT\n"); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/** 63862306a36Sopenharmony_ci * ufs_put_super_internal() - put on-disk intrenal structures 63962306a36Sopenharmony_ci * @sb: pointer to super_block structure 64062306a36Sopenharmony_ci * Put on-disk structures associated with cylinder groups 64162306a36Sopenharmony_ci * and write them back to disk, also update cs_total on disk 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_cistatic void ufs_put_super_internal(struct super_block *sb) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct ufs_sb_info *sbi = UFS_SB(sb); 64662306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = sbi->s_uspi; 64762306a36Sopenharmony_ci struct ufs_buffer_head * ubh; 64862306a36Sopenharmony_ci unsigned char * base, * space; 64962306a36Sopenharmony_ci unsigned blks, size, i; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci UFSD("ENTER\n"); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci ufs_put_cstotal(sb); 65562306a36Sopenharmony_ci size = uspi->s_cssize; 65662306a36Sopenharmony_ci blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; 65762306a36Sopenharmony_ci base = space = (char*) sbi->s_csp; 65862306a36Sopenharmony_ci for (i = 0; i < blks; i += uspi->s_fpb) { 65962306a36Sopenharmony_ci size = uspi->s_bsize; 66062306a36Sopenharmony_ci if (i + uspi->s_fpb > blks) 66162306a36Sopenharmony_ci size = (blks - i) * uspi->s_fsize; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci ubh = ubh_bread(sb, uspi->s_csaddr + i, size); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci ubh_memcpyubh (ubh, space, size); 66662306a36Sopenharmony_ci space += size; 66762306a36Sopenharmony_ci ubh_mark_buffer_uptodate (ubh, 1); 66862306a36Sopenharmony_ci ubh_mark_buffer_dirty (ubh); 66962306a36Sopenharmony_ci ubh_brelse (ubh); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci for (i = 0; i < sbi->s_cg_loaded; i++) { 67262306a36Sopenharmony_ci ufs_put_cylinder (sb, i); 67362306a36Sopenharmony_ci kfree (sbi->s_ucpi[i]); 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci for (; i < UFS_MAX_GROUP_LOADED; i++) 67662306a36Sopenharmony_ci kfree (sbi->s_ucpi[i]); 67762306a36Sopenharmony_ci for (i = 0; i < uspi->s_ncg; i++) 67862306a36Sopenharmony_ci brelse (sbi->s_ucg[i]); 67962306a36Sopenharmony_ci kfree (sbi->s_ucg); 68062306a36Sopenharmony_ci kfree (base); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci UFSD("EXIT\n"); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic int ufs_sync_fs(struct super_block *sb, int wait) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 68862306a36Sopenharmony_ci struct ufs_super_block_first * usb1; 68962306a36Sopenharmony_ci struct ufs_super_block_third * usb3; 69062306a36Sopenharmony_ci unsigned flags; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci mutex_lock(&UFS_SB(sb)->s_lock); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci UFSD("ENTER\n"); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci flags = UFS_SB(sb)->s_flags; 69762306a36Sopenharmony_ci uspi = UFS_SB(sb)->s_uspi; 69862306a36Sopenharmony_ci usb1 = ubh_get_usb_first(uspi); 69962306a36Sopenharmony_ci usb3 = ubh_get_usb_third(uspi); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci usb1->fs_time = ufs_get_seconds(sb); 70262306a36Sopenharmony_ci if ((flags & UFS_ST_MASK) == UFS_ST_SUN || 70362306a36Sopenharmony_ci (flags & UFS_ST_MASK) == UFS_ST_SUNOS || 70462306a36Sopenharmony_ci (flags & UFS_ST_MASK) == UFS_ST_SUNx86) 70562306a36Sopenharmony_ci ufs_set_fs_state(sb, usb1, usb3, 70662306a36Sopenharmony_ci UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); 70762306a36Sopenharmony_ci ufs_put_cstotal(sb); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci UFSD("EXIT\n"); 71062306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return 0; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic void delayed_sync_fs(struct work_struct *work) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct ufs_sb_info *sbi; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci sbi = container_of(work, struct ufs_sb_info, sync_work.work); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci spin_lock(&sbi->work_lock); 72262306a36Sopenharmony_ci sbi->work_queued = 0; 72362306a36Sopenharmony_ci spin_unlock(&sbi->work_lock); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci ufs_sync_fs(sbi->sb, 1); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_civoid ufs_mark_sb_dirty(struct super_block *sb) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct ufs_sb_info *sbi = UFS_SB(sb); 73162306a36Sopenharmony_ci unsigned long delay; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci spin_lock(&sbi->work_lock); 73462306a36Sopenharmony_ci if (!sbi->work_queued) { 73562306a36Sopenharmony_ci delay = msecs_to_jiffies(dirty_writeback_interval * 10); 73662306a36Sopenharmony_ci queue_delayed_work(system_long_wq, &sbi->sync_work, delay); 73762306a36Sopenharmony_ci sbi->work_queued = 1; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci spin_unlock(&sbi->work_lock); 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic void ufs_put_super(struct super_block *sb) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct ufs_sb_info * sbi = UFS_SB(sb); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci UFSD("ENTER\n"); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (!sb_rdonly(sb)) 74962306a36Sopenharmony_ci ufs_put_super_internal(sb); 75062306a36Sopenharmony_ci cancel_delayed_work_sync(&sbi->sync_work); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ubh_brelse_uspi (sbi->s_uspi); 75362306a36Sopenharmony_ci kfree (sbi->s_uspi); 75462306a36Sopenharmony_ci kfree (sbi); 75562306a36Sopenharmony_ci sb->s_fs_info = NULL; 75662306a36Sopenharmony_ci UFSD("EXIT\n"); 75762306a36Sopenharmony_ci return; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic u64 ufs_max_bytes(struct super_block *sb) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 76362306a36Sopenharmony_ci int bits = uspi->s_apbshift; 76462306a36Sopenharmony_ci u64 res; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (bits > 21) 76762306a36Sopenharmony_ci res = ~0ULL; 76862306a36Sopenharmony_ci else 76962306a36Sopenharmony_ci res = UFS_NDADDR + (1LL << bits) + (1LL << (2*bits)) + 77062306a36Sopenharmony_ci (1LL << (3*bits)); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (res >= (MAX_LFS_FILESIZE >> uspi->s_bshift)) 77362306a36Sopenharmony_ci return MAX_LFS_FILESIZE; 77462306a36Sopenharmony_ci return res << uspi->s_bshift; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic int ufs_fill_super(struct super_block *sb, void *data, int silent) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct ufs_sb_info * sbi; 78062306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 78162306a36Sopenharmony_ci struct ufs_super_block_first * usb1; 78262306a36Sopenharmony_ci struct ufs_super_block_second * usb2; 78362306a36Sopenharmony_ci struct ufs_super_block_third * usb3; 78462306a36Sopenharmony_ci struct ufs_buffer_head * ubh; 78562306a36Sopenharmony_ci struct inode *inode; 78662306a36Sopenharmony_ci unsigned block_size, super_block_size; 78762306a36Sopenharmony_ci unsigned flags; 78862306a36Sopenharmony_ci unsigned super_block_offset; 78962306a36Sopenharmony_ci unsigned maxsymlen; 79062306a36Sopenharmony_ci int ret = -EINVAL; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci uspi = NULL; 79362306a36Sopenharmony_ci ubh = NULL; 79462306a36Sopenharmony_ci flags = 0; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci UFSD("ENTER\n"); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci#ifndef CONFIG_UFS_FS_WRITE 79962306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 80062306a36Sopenharmony_ci pr_err("ufs was compiled with read-only support, can't be mounted as read-write\n"); 80162306a36Sopenharmony_ci return -EROFS; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci#endif 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci sbi = kzalloc(sizeof(struct ufs_sb_info), GFP_KERNEL); 80662306a36Sopenharmony_ci if (!sbi) 80762306a36Sopenharmony_ci goto failed_nomem; 80862306a36Sopenharmony_ci sb->s_fs_info = sbi; 80962306a36Sopenharmony_ci sbi->sb = sb; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci UFSD("flag %u\n", (int)(sb_rdonly(sb))); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci mutex_init(&sbi->s_lock); 81462306a36Sopenharmony_ci spin_lock_init(&sbi->work_lock); 81562306a36Sopenharmony_ci INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs); 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * Set default mount options 81862306a36Sopenharmony_ci * Parse mount options 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_ci sbi->s_mount_opt = 0; 82162306a36Sopenharmony_ci ufs_set_opt (sbi->s_mount_opt, ONERROR_LOCK); 82262306a36Sopenharmony_ci if (!ufs_parse_options ((char *) data, &sbi->s_mount_opt)) { 82362306a36Sopenharmony_ci pr_err("wrong mount options\n"); 82462306a36Sopenharmony_ci goto failed; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci if (!(sbi->s_mount_opt & UFS_MOUNT_UFSTYPE)) { 82762306a36Sopenharmony_ci if (!silent) 82862306a36Sopenharmony_ci pr_err("You didn't specify the type of your ufs filesystem\n\n" 82962306a36Sopenharmony_ci "mount -t ufs -o ufstype=" 83062306a36Sopenharmony_ci "sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|nextstep-cd|openstep ...\n\n" 83162306a36Sopenharmony_ci ">>>WARNING<<< Wrong ufstype may corrupt your filesystem, " 83262306a36Sopenharmony_ci "default is ufstype=old\n"); 83362306a36Sopenharmony_ci ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD); 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci uspi = kzalloc(sizeof(struct ufs_sb_private_info), GFP_KERNEL); 83762306a36Sopenharmony_ci sbi->s_uspi = uspi; 83862306a36Sopenharmony_ci if (!uspi) 83962306a36Sopenharmony_ci goto failed; 84062306a36Sopenharmony_ci uspi->s_dirblksize = UFS_SECTOR_SIZE; 84162306a36Sopenharmony_ci super_block_offset=UFS_SBLOCK; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci sb->s_maxbytes = MAX_LFS_FILESIZE; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci sb->s_time_gran = NSEC_PER_SEC; 84662306a36Sopenharmony_ci sb->s_time_min = S32_MIN; 84762306a36Sopenharmony_ci sb->s_time_max = S32_MAX; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) { 85062306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_44BSD: 85162306a36Sopenharmony_ci UFSD("ufstype=44bsd\n"); 85262306a36Sopenharmony_ci uspi->s_fsize = block_size = 512; 85362306a36Sopenharmony_ci uspi->s_fmask = ~(512 - 1); 85462306a36Sopenharmony_ci uspi->s_fshift = 9; 85562306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 1536; 85662306a36Sopenharmony_ci uspi->s_sbbase = 0; 85762306a36Sopenharmony_ci flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_UFS2: 86062306a36Sopenharmony_ci UFSD("ufstype=ufs2\n"); 86162306a36Sopenharmony_ci super_block_offset=SBLOCK_UFS2; 86262306a36Sopenharmony_ci uspi->s_fsize = block_size = 512; 86362306a36Sopenharmony_ci uspi->s_fmask = ~(512 - 1); 86462306a36Sopenharmony_ci uspi->s_fshift = 9; 86562306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 1536; 86662306a36Sopenharmony_ci uspi->s_sbbase = 0; 86762306a36Sopenharmony_ci sb->s_time_gran = 1; 86862306a36Sopenharmony_ci sb->s_time_min = S64_MIN; 86962306a36Sopenharmony_ci sb->s_time_max = S64_MAX; 87062306a36Sopenharmony_ci flags |= UFS_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; 87162306a36Sopenharmony_ci break; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_SUN: 87462306a36Sopenharmony_ci UFSD("ufstype=sun\n"); 87562306a36Sopenharmony_ci uspi->s_fsize = block_size = 1024; 87662306a36Sopenharmony_ci uspi->s_fmask = ~(1024 - 1); 87762306a36Sopenharmony_ci uspi->s_fshift = 10; 87862306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 2048; 87962306a36Sopenharmony_ci uspi->s_sbbase = 0; 88062306a36Sopenharmony_ci uspi->s_maxsymlinklen = 0; /* Not supported on disk */ 88162306a36Sopenharmony_ci flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN; 88262306a36Sopenharmony_ci break; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_SUNOS: 88562306a36Sopenharmony_ci UFSD("ufstype=sunos\n"); 88662306a36Sopenharmony_ci uspi->s_fsize = block_size = 1024; 88762306a36Sopenharmony_ci uspi->s_fmask = ~(1024 - 1); 88862306a36Sopenharmony_ci uspi->s_fshift = 10; 88962306a36Sopenharmony_ci uspi->s_sbsize = 2048; 89062306a36Sopenharmony_ci super_block_size = 2048; 89162306a36Sopenharmony_ci uspi->s_sbbase = 0; 89262306a36Sopenharmony_ci uspi->s_maxsymlinklen = 0; /* Not supported on disk */ 89362306a36Sopenharmony_ci flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_SUNOS | UFS_CG_SUN; 89462306a36Sopenharmony_ci break; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_SUNx86: 89762306a36Sopenharmony_ci UFSD("ufstype=sunx86\n"); 89862306a36Sopenharmony_ci uspi->s_fsize = block_size = 1024; 89962306a36Sopenharmony_ci uspi->s_fmask = ~(1024 - 1); 90062306a36Sopenharmony_ci uspi->s_fshift = 10; 90162306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 2048; 90262306a36Sopenharmony_ci uspi->s_sbbase = 0; 90362306a36Sopenharmony_ci uspi->s_maxsymlinklen = 0; /* Not supported on disk */ 90462306a36Sopenharmony_ci flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN; 90562306a36Sopenharmony_ci break; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_OLD: 90862306a36Sopenharmony_ci UFSD("ufstype=old\n"); 90962306a36Sopenharmony_ci uspi->s_fsize = block_size = 1024; 91062306a36Sopenharmony_ci uspi->s_fmask = ~(1024 - 1); 91162306a36Sopenharmony_ci uspi->s_fshift = 10; 91262306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 2048; 91362306a36Sopenharmony_ci uspi->s_sbbase = 0; 91462306a36Sopenharmony_ci flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; 91562306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 91662306a36Sopenharmony_ci if (!silent) 91762306a36Sopenharmony_ci pr_info("ufstype=old is supported read-only\n"); 91862306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci break; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_NEXTSTEP: 92362306a36Sopenharmony_ci UFSD("ufstype=nextstep\n"); 92462306a36Sopenharmony_ci uspi->s_fsize = block_size = 1024; 92562306a36Sopenharmony_ci uspi->s_fmask = ~(1024 - 1); 92662306a36Sopenharmony_ci uspi->s_fshift = 10; 92762306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 2048; 92862306a36Sopenharmony_ci uspi->s_sbbase = 0; 92962306a36Sopenharmony_ci uspi->s_dirblksize = 1024; 93062306a36Sopenharmony_ci flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; 93162306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 93262306a36Sopenharmony_ci if (!silent) 93362306a36Sopenharmony_ci pr_info("ufstype=nextstep is supported read-only\n"); 93462306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci break; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD: 93962306a36Sopenharmony_ci UFSD("ufstype=nextstep-cd\n"); 94062306a36Sopenharmony_ci uspi->s_fsize = block_size = 2048; 94162306a36Sopenharmony_ci uspi->s_fmask = ~(2048 - 1); 94262306a36Sopenharmony_ci uspi->s_fshift = 11; 94362306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 2048; 94462306a36Sopenharmony_ci uspi->s_sbbase = 0; 94562306a36Sopenharmony_ci uspi->s_dirblksize = 1024; 94662306a36Sopenharmony_ci flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; 94762306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 94862306a36Sopenharmony_ci if (!silent) 94962306a36Sopenharmony_ci pr_info("ufstype=nextstep-cd is supported read-only\n"); 95062306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci break; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_OPENSTEP: 95562306a36Sopenharmony_ci UFSD("ufstype=openstep\n"); 95662306a36Sopenharmony_ci uspi->s_fsize = block_size = 1024; 95762306a36Sopenharmony_ci uspi->s_fmask = ~(1024 - 1); 95862306a36Sopenharmony_ci uspi->s_fshift = 10; 95962306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 2048; 96062306a36Sopenharmony_ci uspi->s_sbbase = 0; 96162306a36Sopenharmony_ci uspi->s_dirblksize = 1024; 96262306a36Sopenharmony_ci flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; 96362306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 96462306a36Sopenharmony_ci if (!silent) 96562306a36Sopenharmony_ci pr_info("ufstype=openstep is supported read-only\n"); 96662306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci break; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci case UFS_MOUNT_UFSTYPE_HP: 97162306a36Sopenharmony_ci UFSD("ufstype=hp\n"); 97262306a36Sopenharmony_ci uspi->s_fsize = block_size = 1024; 97362306a36Sopenharmony_ci uspi->s_fmask = ~(1024 - 1); 97462306a36Sopenharmony_ci uspi->s_fshift = 10; 97562306a36Sopenharmony_ci uspi->s_sbsize = super_block_size = 2048; 97662306a36Sopenharmony_ci uspi->s_sbbase = 0; 97762306a36Sopenharmony_ci flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; 97862306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 97962306a36Sopenharmony_ci if (!silent) 98062306a36Sopenharmony_ci pr_info("ufstype=hp is supported read-only\n"); 98162306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci break; 98462306a36Sopenharmony_ci default: 98562306a36Sopenharmony_ci if (!silent) 98662306a36Sopenharmony_ci pr_err("unknown ufstype\n"); 98762306a36Sopenharmony_ci goto failed; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ciagain: 99162306a36Sopenharmony_ci if (!sb_set_blocksize(sb, block_size)) { 99262306a36Sopenharmony_ci pr_err("failed to set blocksize\n"); 99362306a36Sopenharmony_ci goto failed; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* 99762306a36Sopenharmony_ci * read ufs super block from device 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + super_block_offset/block_size, super_block_size); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (!ubh) 100362306a36Sopenharmony_ci goto failed; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci usb1 = ubh_get_usb_first(uspi); 100662306a36Sopenharmony_ci usb2 = ubh_get_usb_second(uspi); 100762306a36Sopenharmony_ci usb3 = ubh_get_usb_third(uspi); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* Sort out mod used on SunOS 4.1.3 for fs_state */ 101062306a36Sopenharmony_ci uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat); 101162306a36Sopenharmony_ci if (((flags & UFS_ST_MASK) == UFS_ST_SUNOS) && 101262306a36Sopenharmony_ci (uspi->s_postblformat != UFS_42POSTBLFMT)) { 101362306a36Sopenharmony_ci flags &= ~UFS_ST_MASK; 101462306a36Sopenharmony_ci flags |= UFS_ST_SUN; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if ((flags & UFS_ST_MASK) == UFS_ST_44BSD && 101862306a36Sopenharmony_ci uspi->s_postblformat == UFS_42POSTBLFMT) { 101962306a36Sopenharmony_ci if (!silent) 102062306a36Sopenharmony_ci pr_err("this is not a 44bsd filesystem"); 102162306a36Sopenharmony_ci goto failed; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* 102562306a36Sopenharmony_ci * Check ufs magic number 102662306a36Sopenharmony_ci */ 102762306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_LE; 102862306a36Sopenharmony_ci switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) { 102962306a36Sopenharmony_ci case UFS_MAGIC: 103062306a36Sopenharmony_ci case UFS_MAGIC_BW: 103162306a36Sopenharmony_ci case UFS2_MAGIC: 103262306a36Sopenharmony_ci case UFS_MAGIC_LFN: 103362306a36Sopenharmony_ci case UFS_MAGIC_FEA: 103462306a36Sopenharmony_ci case UFS_MAGIC_4GB: 103562306a36Sopenharmony_ci goto magic_found; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_BE; 103862306a36Sopenharmony_ci switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) { 103962306a36Sopenharmony_ci case UFS_MAGIC: 104062306a36Sopenharmony_ci case UFS_MAGIC_BW: 104162306a36Sopenharmony_ci case UFS2_MAGIC: 104262306a36Sopenharmony_ci case UFS_MAGIC_LFN: 104362306a36Sopenharmony_ci case UFS_MAGIC_FEA: 104462306a36Sopenharmony_ci case UFS_MAGIC_4GB: 104562306a36Sopenharmony_ci goto magic_found; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if ((((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP) 104962306a36Sopenharmony_ci || ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP_CD) 105062306a36Sopenharmony_ci || ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_OPENSTEP)) 105162306a36Sopenharmony_ci && uspi->s_sbbase < 256) { 105262306a36Sopenharmony_ci ubh_brelse_uspi(uspi); 105362306a36Sopenharmony_ci ubh = NULL; 105462306a36Sopenharmony_ci uspi->s_sbbase += 8; 105562306a36Sopenharmony_ci goto again; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci if (!silent) 105862306a36Sopenharmony_ci pr_err("%s(): bad magic number\n", __func__); 105962306a36Sopenharmony_ci goto failed; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cimagic_found: 106262306a36Sopenharmony_ci /* 106362306a36Sopenharmony_ci * Check block and fragment sizes 106462306a36Sopenharmony_ci */ 106562306a36Sopenharmony_ci uspi->s_bsize = fs32_to_cpu(sb, usb1->fs_bsize); 106662306a36Sopenharmony_ci uspi->s_fsize = fs32_to_cpu(sb, usb1->fs_fsize); 106762306a36Sopenharmony_ci uspi->s_sbsize = fs32_to_cpu(sb, usb1->fs_sbsize); 106862306a36Sopenharmony_ci uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask); 106962306a36Sopenharmony_ci uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (!is_power_of_2(uspi->s_fsize)) { 107262306a36Sopenharmony_ci pr_err("%s(): fragment size %u is not a power of 2\n", 107362306a36Sopenharmony_ci __func__, uspi->s_fsize); 107462306a36Sopenharmony_ci goto failed; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci if (uspi->s_fsize < 512) { 107762306a36Sopenharmony_ci pr_err("%s(): fragment size %u is too small\n", 107862306a36Sopenharmony_ci __func__, uspi->s_fsize); 107962306a36Sopenharmony_ci goto failed; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci if (uspi->s_fsize > 4096) { 108262306a36Sopenharmony_ci pr_err("%s(): fragment size %u is too large\n", 108362306a36Sopenharmony_ci __func__, uspi->s_fsize); 108462306a36Sopenharmony_ci goto failed; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci if (!is_power_of_2(uspi->s_bsize)) { 108762306a36Sopenharmony_ci pr_err("%s(): block size %u is not a power of 2\n", 108862306a36Sopenharmony_ci __func__, uspi->s_bsize); 108962306a36Sopenharmony_ci goto failed; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci if (uspi->s_bsize < 4096) { 109262306a36Sopenharmony_ci pr_err("%s(): block size %u is too small\n", 109362306a36Sopenharmony_ci __func__, uspi->s_bsize); 109462306a36Sopenharmony_ci goto failed; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci if (uspi->s_bsize / uspi->s_fsize > 8) { 109762306a36Sopenharmony_ci pr_err("%s(): too many fragments per block (%u)\n", 109862306a36Sopenharmony_ci __func__, uspi->s_bsize / uspi->s_fsize); 109962306a36Sopenharmony_ci goto failed; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) { 110262306a36Sopenharmony_ci ubh_brelse_uspi(uspi); 110362306a36Sopenharmony_ci ubh = NULL; 110462306a36Sopenharmony_ci block_size = uspi->s_fsize; 110562306a36Sopenharmony_ci super_block_size = uspi->s_sbsize; 110662306a36Sopenharmony_ci UFSD("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size); 110762306a36Sopenharmony_ci goto again; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci sbi->s_flags = flags;/*after that line some functions use s_flags*/ 111162306a36Sopenharmony_ci ufs_print_super_stuff(sb, usb1, usb2, usb3); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* 111462306a36Sopenharmony_ci * Check, if file system was correctly unmounted. 111562306a36Sopenharmony_ci * If not, make it read only. 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ci if (((flags & UFS_ST_MASK) == UFS_ST_44BSD) || 111862306a36Sopenharmony_ci ((flags & UFS_ST_MASK) == UFS_ST_OLD) || 111962306a36Sopenharmony_ci (((flags & UFS_ST_MASK) == UFS_ST_SUN || 112062306a36Sopenharmony_ci (flags & UFS_ST_MASK) == UFS_ST_SUNOS || 112162306a36Sopenharmony_ci (flags & UFS_ST_MASK) == UFS_ST_SUNx86) && 112262306a36Sopenharmony_ci (ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time))))) { 112362306a36Sopenharmony_ci switch(usb1->fs_clean) { 112462306a36Sopenharmony_ci case UFS_FSCLEAN: 112562306a36Sopenharmony_ci UFSD("fs is clean\n"); 112662306a36Sopenharmony_ci break; 112762306a36Sopenharmony_ci case UFS_FSSTABLE: 112862306a36Sopenharmony_ci UFSD("fs is stable\n"); 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci case UFS_FSLOG: 113162306a36Sopenharmony_ci UFSD("fs is logging fs\n"); 113262306a36Sopenharmony_ci break; 113362306a36Sopenharmony_ci case UFS_FSOSF1: 113462306a36Sopenharmony_ci UFSD("fs is DEC OSF/1\n"); 113562306a36Sopenharmony_ci break; 113662306a36Sopenharmony_ci case UFS_FSACTIVE: 113762306a36Sopenharmony_ci pr_err("%s(): fs is active\n", __func__); 113862306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 113962306a36Sopenharmony_ci break; 114062306a36Sopenharmony_ci case UFS_FSBAD: 114162306a36Sopenharmony_ci pr_err("%s(): fs is bad\n", __func__); 114262306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 114362306a36Sopenharmony_ci break; 114462306a36Sopenharmony_ci default: 114562306a36Sopenharmony_ci pr_err("%s(): can't grok fs_clean 0x%x\n", 114662306a36Sopenharmony_ci __func__, usb1->fs_clean); 114762306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 114862306a36Sopenharmony_ci break; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci } else { 115162306a36Sopenharmony_ci pr_err("%s(): fs needs fsck\n", __func__); 115262306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* 115662306a36Sopenharmony_ci * Read ufs_super_block into internal data structures 115762306a36Sopenharmony_ci */ 115862306a36Sopenharmony_ci sb->s_op = &ufs_super_ops; 115962306a36Sopenharmony_ci sb->s_export_op = &ufs_export_ops; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci uspi->s_sblkno = fs32_to_cpu(sb, usb1->fs_sblkno); 116462306a36Sopenharmony_ci uspi->s_cblkno = fs32_to_cpu(sb, usb1->fs_cblkno); 116562306a36Sopenharmony_ci uspi->s_iblkno = fs32_to_cpu(sb, usb1->fs_iblkno); 116662306a36Sopenharmony_ci uspi->s_dblkno = fs32_to_cpu(sb, usb1->fs_dblkno); 116762306a36Sopenharmony_ci uspi->s_cgoffset = fs32_to_cpu(sb, usb1->fs_cgoffset); 116862306a36Sopenharmony_ci uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { 117162306a36Sopenharmony_ci uspi->s_size = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size); 117262306a36Sopenharmony_ci uspi->s_dsize = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize); 117362306a36Sopenharmony_ci } else { 117462306a36Sopenharmony_ci uspi->s_size = fs32_to_cpu(sb, usb1->fs_size); 117562306a36Sopenharmony_ci uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize); 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci uspi->s_ncg = fs32_to_cpu(sb, usb1->fs_ncg); 117962306a36Sopenharmony_ci /* s_bsize already set */ 118062306a36Sopenharmony_ci /* s_fsize already set */ 118162306a36Sopenharmony_ci uspi->s_fpb = fs32_to_cpu(sb, usb1->fs_frag); 118262306a36Sopenharmony_ci uspi->s_minfree = fs32_to_cpu(sb, usb1->fs_minfree); 118362306a36Sopenharmony_ci uspi->s_bmask = fs32_to_cpu(sb, usb1->fs_bmask); 118462306a36Sopenharmony_ci uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask); 118562306a36Sopenharmony_ci uspi->s_bshift = fs32_to_cpu(sb, usb1->fs_bshift); 118662306a36Sopenharmony_ci uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift); 118762306a36Sopenharmony_ci UFSD("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift, 118862306a36Sopenharmony_ci uspi->s_fshift); 118962306a36Sopenharmony_ci uspi->s_fpbshift = fs32_to_cpu(sb, usb1->fs_fragshift); 119062306a36Sopenharmony_ci uspi->s_fsbtodb = fs32_to_cpu(sb, usb1->fs_fsbtodb); 119162306a36Sopenharmony_ci /* s_sbsize already set */ 119262306a36Sopenharmony_ci uspi->s_csmask = fs32_to_cpu(sb, usb1->fs_csmask); 119362306a36Sopenharmony_ci uspi->s_csshift = fs32_to_cpu(sb, usb1->fs_csshift); 119462306a36Sopenharmony_ci uspi->s_nindir = fs32_to_cpu(sb, usb1->fs_nindir); 119562306a36Sopenharmony_ci uspi->s_inopb = fs32_to_cpu(sb, usb1->fs_inopb); 119662306a36Sopenharmony_ci uspi->s_nspf = fs32_to_cpu(sb, usb1->fs_nspf); 119762306a36Sopenharmony_ci uspi->s_npsect = ufs_get_fs_npsect(sb, usb1, usb3); 119862306a36Sopenharmony_ci uspi->s_interleave = fs32_to_cpu(sb, usb1->fs_interleave); 119962306a36Sopenharmony_ci uspi->s_trackskew = fs32_to_cpu(sb, usb1->fs_trackskew); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (uspi->fs_magic == UFS2_MAGIC) 120262306a36Sopenharmony_ci uspi->s_csaddr = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr); 120362306a36Sopenharmony_ci else 120462306a36Sopenharmony_ci uspi->s_csaddr = fs32_to_cpu(sb, usb1->fs_csaddr); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci uspi->s_cssize = fs32_to_cpu(sb, usb1->fs_cssize); 120762306a36Sopenharmony_ci uspi->s_cgsize = fs32_to_cpu(sb, usb1->fs_cgsize); 120862306a36Sopenharmony_ci uspi->s_ntrak = fs32_to_cpu(sb, usb1->fs_ntrak); 120962306a36Sopenharmony_ci uspi->s_nsect = fs32_to_cpu(sb, usb1->fs_nsect); 121062306a36Sopenharmony_ci uspi->s_spc = fs32_to_cpu(sb, usb1->fs_spc); 121162306a36Sopenharmony_ci uspi->s_ipg = fs32_to_cpu(sb, usb1->fs_ipg); 121262306a36Sopenharmony_ci uspi->s_fpg = fs32_to_cpu(sb, usb1->fs_fpg); 121362306a36Sopenharmony_ci uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_un.fs_u1.fs_cpc); 121462306a36Sopenharmony_ci uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_contigsumsize); 121562306a36Sopenharmony_ci uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3); 121662306a36Sopenharmony_ci uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3); 121762306a36Sopenharmony_ci uspi->s_nrpos = fs32_to_cpu(sb, usb3->fs_nrpos); 121862306a36Sopenharmony_ci uspi->s_postbloff = fs32_to_cpu(sb, usb3->fs_postbloff); 121962306a36Sopenharmony_ci uspi->s_rotbloff = fs32_to_cpu(sb, usb3->fs_rotbloff); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci uspi->s_root_blocks = mul_u64_u32_div(uspi->s_dsize, 122262306a36Sopenharmony_ci uspi->s_minfree, 100); 122362306a36Sopenharmony_ci if (uspi->s_minfree <= 5) { 122462306a36Sopenharmony_ci uspi->s_time_to_space = ~0ULL; 122562306a36Sopenharmony_ci uspi->s_space_to_time = 0; 122662306a36Sopenharmony_ci usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTSPACE); 122762306a36Sopenharmony_ci } else { 122862306a36Sopenharmony_ci uspi->s_time_to_space = (uspi->s_root_blocks / 2) + 1; 122962306a36Sopenharmony_ci uspi->s_space_to_time = mul_u64_u32_div(uspi->s_dsize, 123062306a36Sopenharmony_ci uspi->s_minfree - 2, 100) - 1; 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* 123462306a36Sopenharmony_ci * Compute another frequently used values 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_ci uspi->s_fpbmask = uspi->s_fpb - 1; 123762306a36Sopenharmony_ci if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 123862306a36Sopenharmony_ci uspi->s_apbshift = uspi->s_bshift - 3; 123962306a36Sopenharmony_ci else 124062306a36Sopenharmony_ci uspi->s_apbshift = uspi->s_bshift - 2; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci uspi->s_2apbshift = uspi->s_apbshift * 2; 124362306a36Sopenharmony_ci uspi->s_3apbshift = uspi->s_apbshift * 3; 124462306a36Sopenharmony_ci uspi->s_apb = 1 << uspi->s_apbshift; 124562306a36Sopenharmony_ci uspi->s_2apb = 1 << uspi->s_2apbshift; 124662306a36Sopenharmony_ci uspi->s_3apb = 1 << uspi->s_3apbshift; 124762306a36Sopenharmony_ci uspi->s_apbmask = uspi->s_apb - 1; 124862306a36Sopenharmony_ci uspi->s_nspfshift = uspi->s_fshift - UFS_SECTOR_BITS; 124962306a36Sopenharmony_ci uspi->s_nspb = uspi->s_nspf << uspi->s_fpbshift; 125062306a36Sopenharmony_ci uspi->s_inopf = uspi->s_inopb >> uspi->s_fpbshift; 125162306a36Sopenharmony_ci uspi->s_bpf = uspi->s_fsize << 3; 125262306a36Sopenharmony_ci uspi->s_bpfshift = uspi->s_fshift + 3; 125362306a36Sopenharmony_ci uspi->s_bpfmask = uspi->s_bpf - 1; 125462306a36Sopenharmony_ci if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_44BSD || 125562306a36Sopenharmony_ci (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_UFS2) 125662306a36Sopenharmony_ci uspi->s_maxsymlinklen = 125762306a36Sopenharmony_ci fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (uspi->fs_magic == UFS2_MAGIC) 126062306a36Sopenharmony_ci maxsymlen = 2 * 4 * (UFS_NDADDR + UFS_NINDIR); 126162306a36Sopenharmony_ci else 126262306a36Sopenharmony_ci maxsymlen = 4 * (UFS_NDADDR + UFS_NINDIR); 126362306a36Sopenharmony_ci if (uspi->s_maxsymlinklen > maxsymlen) { 126462306a36Sopenharmony_ci ufs_warning(sb, __func__, "ufs_read_super: excessive maximum " 126562306a36Sopenharmony_ci "fast symlink size (%u)\n", uspi->s_maxsymlinklen); 126662306a36Sopenharmony_ci uspi->s_maxsymlinklen = maxsymlen; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci sb->s_maxbytes = ufs_max_bytes(sb); 126962306a36Sopenharmony_ci sb->s_max_links = UFS_LINK_MAX; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci inode = ufs_iget(sb, UFS_ROOTINO); 127262306a36Sopenharmony_ci if (IS_ERR(inode)) { 127362306a36Sopenharmony_ci ret = PTR_ERR(inode); 127462306a36Sopenharmony_ci goto failed; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci sb->s_root = d_make_root(inode); 127762306a36Sopenharmony_ci if (!sb->s_root) { 127862306a36Sopenharmony_ci ret = -ENOMEM; 127962306a36Sopenharmony_ci goto failed; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci ufs_setup_cstotal(sb); 128362306a36Sopenharmony_ci /* 128462306a36Sopenharmony_ci * Read cylinder group structures 128562306a36Sopenharmony_ci */ 128662306a36Sopenharmony_ci if (!sb_rdonly(sb)) 128762306a36Sopenharmony_ci if (!ufs_read_cylinder_structures(sb)) 128862306a36Sopenharmony_ci goto failed; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci UFSD("EXIT\n"); 129162306a36Sopenharmony_ci return 0; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_cifailed: 129462306a36Sopenharmony_ci if (ubh) 129562306a36Sopenharmony_ci ubh_brelse_uspi (uspi); 129662306a36Sopenharmony_ci kfree (uspi); 129762306a36Sopenharmony_ci kfree(sbi); 129862306a36Sopenharmony_ci sb->s_fs_info = NULL; 129962306a36Sopenharmony_ci UFSD("EXIT (FAILED)\n"); 130062306a36Sopenharmony_ci return ret; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_cifailed_nomem: 130362306a36Sopenharmony_ci UFSD("EXIT (NOMEM)\n"); 130462306a36Sopenharmony_ci return -ENOMEM; 130562306a36Sopenharmony_ci} 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cistatic int ufs_remount (struct super_block *sb, int *mount_flags, char *data) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 131062306a36Sopenharmony_ci struct ufs_super_block_first * usb1; 131162306a36Sopenharmony_ci struct ufs_super_block_third * usb3; 131262306a36Sopenharmony_ci unsigned new_mount_opt, ufstype; 131362306a36Sopenharmony_ci unsigned flags; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci sync_filesystem(sb); 131662306a36Sopenharmony_ci mutex_lock(&UFS_SB(sb)->s_lock); 131762306a36Sopenharmony_ci uspi = UFS_SB(sb)->s_uspi; 131862306a36Sopenharmony_ci flags = UFS_SB(sb)->s_flags; 131962306a36Sopenharmony_ci usb1 = ubh_get_usb_first(uspi); 132062306a36Sopenharmony_ci usb3 = ubh_get_usb_third(uspi); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci /* 132362306a36Sopenharmony_ci * Allow the "check" option to be passed as a remount option. 132462306a36Sopenharmony_ci * It is not possible to change ufstype option during remount 132562306a36Sopenharmony_ci */ 132662306a36Sopenharmony_ci ufstype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE; 132762306a36Sopenharmony_ci new_mount_opt = 0; 132862306a36Sopenharmony_ci ufs_set_opt (new_mount_opt, ONERROR_LOCK); 132962306a36Sopenharmony_ci if (!ufs_parse_options (data, &new_mount_opt)) { 133062306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 133162306a36Sopenharmony_ci return -EINVAL; 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) { 133462306a36Sopenharmony_ci new_mount_opt |= ufstype; 133562306a36Sopenharmony_ci } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { 133662306a36Sopenharmony_ci pr_err("ufstype can't be changed during remount\n"); 133762306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 133862306a36Sopenharmony_ci return -EINVAL; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci if ((bool)(*mount_flags & SB_RDONLY) == sb_rdonly(sb)) { 134262306a36Sopenharmony_ci UFS_SB(sb)->s_mount_opt = new_mount_opt; 134362306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 134462306a36Sopenharmony_ci return 0; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci /* 134862306a36Sopenharmony_ci * fs was mouted as rw, remounting ro 134962306a36Sopenharmony_ci */ 135062306a36Sopenharmony_ci if (*mount_flags & SB_RDONLY) { 135162306a36Sopenharmony_ci ufs_put_super_internal(sb); 135262306a36Sopenharmony_ci usb1->fs_time = ufs_get_seconds(sb); 135362306a36Sopenharmony_ci if ((flags & UFS_ST_MASK) == UFS_ST_SUN 135462306a36Sopenharmony_ci || (flags & UFS_ST_MASK) == UFS_ST_SUNOS 135562306a36Sopenharmony_ci || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) 135662306a36Sopenharmony_ci ufs_set_fs_state(sb, usb1, usb3, 135762306a36Sopenharmony_ci UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); 135862306a36Sopenharmony_ci ubh_mark_buffer_dirty (USPI_UBH(uspi)); 135962306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 136062306a36Sopenharmony_ci } else { 136162306a36Sopenharmony_ci /* 136262306a36Sopenharmony_ci * fs was mounted as ro, remounting rw 136362306a36Sopenharmony_ci */ 136462306a36Sopenharmony_ci#ifndef CONFIG_UFS_FS_WRITE 136562306a36Sopenharmony_ci pr_err("ufs was compiled with read-only support, can't be mounted as read-write\n"); 136662306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 136762306a36Sopenharmony_ci return -EINVAL; 136862306a36Sopenharmony_ci#else 136962306a36Sopenharmony_ci if (ufstype != UFS_MOUNT_UFSTYPE_SUN && 137062306a36Sopenharmony_ci ufstype != UFS_MOUNT_UFSTYPE_SUNOS && 137162306a36Sopenharmony_ci ufstype != UFS_MOUNT_UFSTYPE_44BSD && 137262306a36Sopenharmony_ci ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && 137362306a36Sopenharmony_ci ufstype != UFS_MOUNT_UFSTYPE_UFS2) { 137462306a36Sopenharmony_ci pr_err("this ufstype is read-only supported\n"); 137562306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 137662306a36Sopenharmony_ci return -EINVAL; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci if (!ufs_read_cylinder_structures(sb)) { 137962306a36Sopenharmony_ci pr_err("failed during remounting\n"); 138062306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 138162306a36Sopenharmony_ci return -EPERM; 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci sb->s_flags &= ~SB_RDONLY; 138462306a36Sopenharmony_ci#endif 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci UFS_SB(sb)->s_mount_opt = new_mount_opt; 138762306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 138862306a36Sopenharmony_ci return 0; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic int ufs_show_options(struct seq_file *seq, struct dentry *root) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci struct ufs_sb_info *sbi = UFS_SB(root->d_sb); 139462306a36Sopenharmony_ci unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE; 139562306a36Sopenharmony_ci const struct match_token *tp = tokens; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci while (tp->token != Opt_onerror_panic && tp->token != mval) 139862306a36Sopenharmony_ci ++tp; 139962306a36Sopenharmony_ci BUG_ON(tp->token == Opt_onerror_panic); 140062306a36Sopenharmony_ci seq_printf(seq, ",%s", tp->pattern); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci mval = sbi->s_mount_opt & UFS_MOUNT_ONERROR; 140362306a36Sopenharmony_ci while (tp->token != Opt_err && tp->token != mval) 140462306a36Sopenharmony_ci ++tp; 140562306a36Sopenharmony_ci BUG_ON(tp->token == Opt_err); 140662306a36Sopenharmony_ci seq_printf(seq, ",%s", tp->pattern); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci return 0; 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_cistatic int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) 141262306a36Sopenharmony_ci{ 141362306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 141462306a36Sopenharmony_ci struct ufs_sb_private_info *uspi= UFS_SB(sb)->s_uspi; 141562306a36Sopenharmony_ci unsigned flags = UFS_SB(sb)->s_flags; 141662306a36Sopenharmony_ci u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci mutex_lock(&UFS_SB(sb)->s_lock); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 142162306a36Sopenharmony_ci buf->f_type = UFS2_MAGIC; 142262306a36Sopenharmony_ci else 142362306a36Sopenharmony_ci buf->f_type = UFS_MAGIC; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci buf->f_blocks = uspi->s_dsize; 142662306a36Sopenharmony_ci buf->f_bfree = ufs_freefrags(uspi); 142762306a36Sopenharmony_ci buf->f_ffree = uspi->cs_total.cs_nifree; 142862306a36Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 142962306a36Sopenharmony_ci buf->f_bavail = (buf->f_bfree > uspi->s_root_blocks) 143062306a36Sopenharmony_ci ? (buf->f_bfree - uspi->s_root_blocks) : 0; 143162306a36Sopenharmony_ci buf->f_files = uspi->s_ncg * uspi->s_ipg; 143262306a36Sopenharmony_ci buf->f_namelen = UFS_MAXNAMLEN; 143362306a36Sopenharmony_ci buf->f_fsid = u64_to_fsid(id); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci mutex_unlock(&UFS_SB(sb)->s_lock); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci return 0; 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_cistatic struct kmem_cache * ufs_inode_cachep; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic struct inode *ufs_alloc_inode(struct super_block *sb) 144362306a36Sopenharmony_ci{ 144462306a36Sopenharmony_ci struct ufs_inode_info *ei; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci ei = alloc_inode_sb(sb, ufs_inode_cachep, GFP_NOFS); 144762306a36Sopenharmony_ci if (!ei) 144862306a36Sopenharmony_ci return NULL; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci inode_set_iversion(&ei->vfs_inode, 1); 145162306a36Sopenharmony_ci seqlock_init(&ei->meta_lock); 145262306a36Sopenharmony_ci mutex_init(&ei->truncate_mutex); 145362306a36Sopenharmony_ci return &ei->vfs_inode; 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_cistatic void ufs_free_in_core_inode(struct inode *inode) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic void init_once(void *foo) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci inode_init_once(&ei->vfs_inode); 146662306a36Sopenharmony_ci} 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_cistatic int __init init_inodecache(void) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci ufs_inode_cachep = kmem_cache_create_usercopy("ufs_inode_cache", 147162306a36Sopenharmony_ci sizeof(struct ufs_inode_info), 0, 147262306a36Sopenharmony_ci (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD| 147362306a36Sopenharmony_ci SLAB_ACCOUNT), 147462306a36Sopenharmony_ci offsetof(struct ufs_inode_info, i_u1.i_symlink), 147562306a36Sopenharmony_ci sizeof_field(struct ufs_inode_info, 147662306a36Sopenharmony_ci i_u1.i_symlink), 147762306a36Sopenharmony_ci init_once); 147862306a36Sopenharmony_ci if (ufs_inode_cachep == NULL) 147962306a36Sopenharmony_ci return -ENOMEM; 148062306a36Sopenharmony_ci return 0; 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_cistatic void destroy_inodecache(void) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci /* 148662306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 148762306a36Sopenharmony_ci * destroy cache. 148862306a36Sopenharmony_ci */ 148962306a36Sopenharmony_ci rcu_barrier(); 149062306a36Sopenharmony_ci kmem_cache_destroy(ufs_inode_cachep); 149162306a36Sopenharmony_ci} 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_cistatic const struct super_operations ufs_super_ops = { 149462306a36Sopenharmony_ci .alloc_inode = ufs_alloc_inode, 149562306a36Sopenharmony_ci .free_inode = ufs_free_in_core_inode, 149662306a36Sopenharmony_ci .write_inode = ufs_write_inode, 149762306a36Sopenharmony_ci .evict_inode = ufs_evict_inode, 149862306a36Sopenharmony_ci .put_super = ufs_put_super, 149962306a36Sopenharmony_ci .sync_fs = ufs_sync_fs, 150062306a36Sopenharmony_ci .statfs = ufs_statfs, 150162306a36Sopenharmony_ci .remount_fs = ufs_remount, 150262306a36Sopenharmony_ci .show_options = ufs_show_options, 150362306a36Sopenharmony_ci}; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_cistatic struct dentry *ufs_mount(struct file_system_type *fs_type, 150662306a36Sopenharmony_ci int flags, const char *dev_name, void *data) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, ufs_fill_super); 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic struct file_system_type ufs_fs_type = { 151262306a36Sopenharmony_ci .owner = THIS_MODULE, 151362306a36Sopenharmony_ci .name = "ufs", 151462306a36Sopenharmony_ci .mount = ufs_mount, 151562306a36Sopenharmony_ci .kill_sb = kill_block_super, 151662306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 151762306a36Sopenharmony_ci}; 151862306a36Sopenharmony_ciMODULE_ALIAS_FS("ufs"); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_cistatic int __init init_ufs_fs(void) 152162306a36Sopenharmony_ci{ 152262306a36Sopenharmony_ci int err = init_inodecache(); 152362306a36Sopenharmony_ci if (err) 152462306a36Sopenharmony_ci goto out1; 152562306a36Sopenharmony_ci err = register_filesystem(&ufs_fs_type); 152662306a36Sopenharmony_ci if (err) 152762306a36Sopenharmony_ci goto out; 152862306a36Sopenharmony_ci return 0; 152962306a36Sopenharmony_ciout: 153062306a36Sopenharmony_ci destroy_inodecache(); 153162306a36Sopenharmony_ciout1: 153262306a36Sopenharmony_ci return err; 153362306a36Sopenharmony_ci} 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_cistatic void __exit exit_ufs_fs(void) 153662306a36Sopenharmony_ci{ 153762306a36Sopenharmony_ci unregister_filesystem(&ufs_fs_type); 153862306a36Sopenharmony_ci destroy_inodecache(); 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cimodule_init(init_ufs_fs) 154262306a36Sopenharmony_cimodule_exit(exit_ufs_fs) 154362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1544