2005-04-17 02:20:36 +04:00
/*
* linux / fs / ufs / super . c
*
* Copyright ( C ) 1998
* Daniel Pirkl < daniel . pirkl @ email . cz >
* Charles University , Faculty of Mathematics and Physics
*/
/* Derived from
*
* linux / fs / ext2 / super . c
*
* Copyright ( C ) 1992 , 1993 , 1994 , 1995
* Remy Card ( card @ masi . ibp . fr )
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie ( Paris VI )
*
* from
*
* linux / fs / minix / inode . c
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*
* Big - endian to little - endian byte - swapping / bitmaps by
* David S . Miller ( davem @ caip . rutgers . edu ) , 1995
*/
/*
* Inspired by
*
* linux / fs / ufs / super . c
*
* Copyright ( C ) 1996
* Adrian Rodriguez ( adrian @ franklins - tower . rutgers . edu )
* Laboratory for Computer Science Research Computing Facility
* Rutgers , The State University of New Jersey
*
* Copyright ( C ) 1996 Eddie C . Dost ( ecd @ skynet . be )
*
* Kernel module support added on 96 / 04 / 26 by
* Stefan Reinauer < stepan @ home . culture . mipt . ru >
*
* Module usage counts added on 96 / 04 / 29 by
2009-03-22 01:18:57 +03:00
* Gertjan van Wingerde < gwingerde @ gmail . com >
2005-04-17 02:20:36 +04:00
*
* Clean swab support on 19970406 by
* Francois - Rene Rideau < fare @ tunes . org >
*
* 4.4 BSD ( FreeBSD ) support added on February 1 st 1998 by
* Niels Kristian Bech Jensen < nkbj @ image . dk > partially based
* on code by Martin von Loewis < martin @ mira . isdn . cs . tu - berlin . de > .
*
* NeXTstep support added on February 5 th 1998 by
* Niels Kristian Bech Jensen < nkbj @ image . dk > .
*
* write support Daniel Pirkl < daniel . pirkl @ email . cz > 1998
*
* HP / UX hfs filesystem support added by
* Martin K . Petersen < mkp @ mkp . net > , August 1999
*
* UFS2 ( of FreeBSD 5. x ) support added by
* Niraj Kumar < niraj17 @ iitbombay . org > , Jan 2004
*
2007-02-12 11:54:30 +03:00
* UFS2 write support added by
* Evgeniy Dushistov < dushistov @ mail . ru > , 2007
2005-04-17 02:20:36 +04:00
*/
2009-12-16 03:46:51 +03:00
# include <linux/exportfs.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/bitops.h>
# include <stdarg.h>
# include <asm/uaccess.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/slab.h>
# include <linux/time.h>
# include <linux/stat.h>
# include <linux/string.h>
# include <linux/blkdev.h>
# include <linux/init.h>
# include <linux/parser.h>
# include <linux/buffer_head.h>
# include <linux/vfs.h>
2007-07-16 10:41:36 +04:00
# include <linux/log2.h>
2007-10-17 10:26:32 +04:00
# include <linux/mount.h>
# include <linux/seq_file.h>
2005-04-17 02:20:36 +04:00
2008-02-08 15:21:31 +03:00
# include "ufs_fs.h"
2007-10-17 10:26:51 +04:00
# include "ufs.h"
2005-04-17 02:20:36 +04:00
# include "swab.h"
# include "util.h"
2011-01-24 12:14:12 +03:00
void lock_ufs ( struct super_block * sb )
{
# if defined(CONFIG_SMP) || defined (CONFIG_PREEMPT)
struct ufs_sb_info * sbi = UFS_SB ( sb ) ;
mutex_lock ( & sbi - > mutex ) ;
sbi - > mutex_owner = current ;
# endif
}
void unlock_ufs ( struct super_block * sb )
{
# if defined(CONFIG_SMP) || defined (CONFIG_PREEMPT)
struct ufs_sb_info * sbi = UFS_SB ( sb ) ;
sbi - > mutex_owner = NULL ;
mutex_unlock ( & sbi - > mutex ) ;
# endif
}
2009-12-16 03:46:51 +03:00
static struct inode * ufs_nfs_get_inode ( struct super_block * sb , u64 ino , u32 generation )
{
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
struct inode * inode ;
if ( ino < UFS_ROOTINO | | ino > uspi - > s_ncg * uspi - > s_ipg )
return ERR_PTR ( - ESTALE ) ;
inode = ufs_iget ( sb , ino ) ;
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
if ( generation & & inode - > i_generation ! = generation ) {
iput ( inode ) ;
return ERR_PTR ( - ESTALE ) ;
}
return inode ;
}
static struct dentry * ufs_fh_to_dentry ( struct super_block * sb , struct fid * fid ,
int fh_len , int fh_type )
{
return generic_fh_to_dentry ( sb , fid , fh_len , fh_type , ufs_nfs_get_inode ) ;
}
static struct dentry * ufs_fh_to_parent ( struct super_block * sb , struct fid * fid ,
int fh_len , int fh_type )
{
return generic_fh_to_parent ( sb , fid , fh_len , fh_type , ufs_nfs_get_inode ) ;
}
static struct dentry * ufs_get_parent ( struct dentry * child )
{
2012-05-11 00:14:12 +04:00
struct qstr dot_dot = QSTR_INIT ( " .. " , 2 ) ;
2009-12-16 03:46:51 +03:00
ino_t ino ;
ino = ufs_inode_by_name ( child - > d_inode , & dot_dot ) ;
if ( ! ino )
return ERR_PTR ( - ENOENT ) ;
return d_obtain_alias ( ufs_iget ( child - > d_inode - > i_sb , ino ) ) ;
}
static const struct export_operations ufs_export_ops = {
. fh_to_dentry = ufs_fh_to_dentry ,
. fh_to_parent = ufs_fh_to_parent ,
. get_parent = ufs_get_parent ,
} ;
2006-06-25 16:47:24 +04:00
# ifdef CONFIG_UFS_DEBUG
2005-04-17 02:20:36 +04:00
/*
* Print contents of ufs_super_block , useful for debugging
*/
2007-02-12 11:54:31 +03:00
static void ufs_print_super_stuff ( struct super_block * sb ,
2006-06-25 16:47:29 +04:00
struct ufs_super_block_first * usb1 ,
struct ufs_super_block_second * usb2 ,
struct ufs_super_block_third * usb3 )
2005-04-17 02:20:36 +04:00
{
2007-02-12 11:54:31 +03:00
u32 magic = fs32_to_cpu ( sb , usb3 - > fs_magic ) ;
2005-04-17 02:20:36 +04:00
printk ( " ufs_print_super_stuff \n " ) ;
2007-02-12 11:54:31 +03:00
printk ( " magic: 0x%x \n " , magic ) ;
if ( fs32_to_cpu ( sb , usb3 - > fs_magic ) = = UFS2_MAGIC ) {
2006-06-25 16:47:29 +04:00
printk ( " fs_size: %llu \n " , ( unsigned long long )
fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . fs_size ) ) ;
printk ( " fs_dsize: %llu \n " , ( unsigned long long )
fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . fs_dsize ) ) ;
printk ( " bsize: %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_bsize ) ) ;
printk ( " fsize: %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_fsize ) ) ;
printk ( " fs_volname: %s \n " , usb2 - > fs_un . fs_u2 . fs_volname ) ;
printk ( " fs_sblockloc: %llu \n " , ( unsigned long long )
fs64_to_cpu ( sb , usb2 - > fs_un . fs_u2 . fs_sblockloc ) ) ;
printk ( " cs_ndir(No of dirs): %llu \n " , ( unsigned long long )
fs64_to_cpu ( sb , usb2 - > fs_un . fs_u2 . cs_ndir ) ) ;
printk ( " cs_nbfree(No of free blocks): %llu \n " ,
( unsigned long long )
fs64_to_cpu ( sb , usb2 - > fs_un . fs_u2 . cs_nbfree ) ) ;
2007-02-12 11:54:31 +03:00
printk ( KERN_INFO " cs_nifree(Num of free inodes): %llu \n " ,
( unsigned long long )
fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . cs_nifree ) ) ;
printk ( KERN_INFO " cs_nffree(Num of free frags): %llu \n " ,
( unsigned long long )
fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . cs_nffree ) ) ;
2008-02-08 15:20:16 +03:00
printk ( KERN_INFO " fs_maxsymlinklen: %u \n " ,
fs32_to_cpu ( sb , usb3 - > fs_un2 . fs_44 . fs_maxsymlinklen ) ) ;
2006-06-25 16:47:29 +04:00
} else {
printk ( " sblkno: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_sblkno ) ) ;
printk ( " cblkno: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_cblkno ) ) ;
printk ( " iblkno: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_iblkno ) ) ;
printk ( " dblkno: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_dblkno ) ) ;
printk ( " cgoffset: %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_cgoffset ) ) ;
printk ( " ~cgmask: 0x%x \n " ,
~ fs32_to_cpu ( sb , usb1 - > fs_cgmask ) ) ;
printk ( " size: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_size ) ) ;
printk ( " dsize: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_dsize ) ) ;
printk ( " ncg: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_ncg ) ) ;
printk ( " bsize: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_bsize ) ) ;
printk ( " fsize: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_fsize ) ) ;
printk ( " frag: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_frag ) ) ;
printk ( " fragshift: %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_fragshift ) ) ;
printk ( " ~fmask: %u \n " , ~ fs32_to_cpu ( sb , usb1 - > fs_fmask ) ) ;
printk ( " fshift: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_fshift ) ) ;
printk ( " sbsize: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_sbsize ) ) ;
printk ( " spc: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_spc ) ) ;
printk ( " cpg: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_cpg ) ) ;
printk ( " ipg: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_ipg ) ) ;
printk ( " fpg: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_fpg ) ) ;
printk ( " csaddr: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_csaddr ) ) ;
printk ( " cssize: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_cssize ) ) ;
printk ( " cgsize: %u \n " , fs32_to_cpu ( sb , usb1 - > fs_cgsize ) ) ;
printk ( " fstodb: %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_fsbtodb ) ) ;
printk ( " nrpos: %u \n " , fs32_to_cpu ( sb , usb3 - > fs_nrpos ) ) ;
printk ( " ndir %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_cstotal . cs_ndir ) ) ;
printk ( " nifree %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_cstotal . cs_nifree ) ) ;
printk ( " nbfree %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_cstotal . cs_nbfree ) ) ;
printk ( " nffree %u \n " ,
fs32_to_cpu ( sb , usb1 - > fs_cstotal . cs_nffree ) ) ;
}
2005-04-17 02:20:36 +04:00
printk ( " \n " ) ;
}
/*
* Print contents of ufs_cylinder_group , useful for debugging
*/
2006-06-25 16:47:29 +04:00
static void ufs_print_cylinder_stuff ( struct super_block * sb ,
struct ufs_cylinder_group * cg )
2005-04-17 02:20:36 +04:00
{
printk ( " \n ufs_print_cylinder_stuff \n " ) ;
2006-06-25 16:47:28 +04:00
printk ( " size of ucg: %zu \n " , sizeof ( struct ufs_cylinder_group ) ) ;
2005-04-17 02:20:36 +04:00
printk ( " magic: %x \n " , fs32_to_cpu ( sb , cg - > cg_magic ) ) ;
printk ( " time: %u \n " , fs32_to_cpu ( sb , cg - > cg_time ) ) ;
printk ( " cgx: %u \n " , fs32_to_cpu ( sb , cg - > cg_cgx ) ) ;
printk ( " ncyl: %u \n " , fs16_to_cpu ( sb , cg - > cg_ncyl ) ) ;
printk ( " niblk: %u \n " , fs16_to_cpu ( sb , cg - > cg_niblk ) ) ;
printk ( " ndblk: %u \n " , fs32_to_cpu ( sb , cg - > cg_ndblk ) ) ;
printk ( " cs_ndir: %u \n " , fs32_to_cpu ( sb , cg - > cg_cs . cs_ndir ) ) ;
printk ( " cs_nbfree: %u \n " , fs32_to_cpu ( sb , cg - > cg_cs . cs_nbfree ) ) ;
printk ( " cs_nifree: %u \n " , fs32_to_cpu ( sb , cg - > cg_cs . cs_nifree ) ) ;
printk ( " cs_nffree: %u \n " , fs32_to_cpu ( sb , cg - > cg_cs . cs_nffree ) ) ;
printk ( " rotor: %u \n " , fs32_to_cpu ( sb , cg - > cg_rotor ) ) ;
printk ( " frotor: %u \n " , fs32_to_cpu ( sb , cg - > cg_frotor ) ) ;
printk ( " irotor: %u \n " , fs32_to_cpu ( sb , cg - > cg_irotor ) ) ;
printk ( " frsum: %u, %u, %u, %u, %u, %u, %u, %u \n " ,
fs32_to_cpu ( sb , cg - > cg_frsum [ 0 ] ) , fs32_to_cpu ( sb , cg - > cg_frsum [ 1 ] ) ,
fs32_to_cpu ( sb , cg - > cg_frsum [ 2 ] ) , fs32_to_cpu ( sb , cg - > cg_frsum [ 3 ] ) ,
fs32_to_cpu ( sb , cg - > cg_frsum [ 4 ] ) , fs32_to_cpu ( sb , cg - > cg_frsum [ 5 ] ) ,
fs32_to_cpu ( sb , cg - > cg_frsum [ 6 ] ) , fs32_to_cpu ( sb , cg - > cg_frsum [ 7 ] ) ) ;
printk ( " btotoff: %u \n " , fs32_to_cpu ( sb , cg - > cg_btotoff ) ) ;
printk ( " boff: %u \n " , fs32_to_cpu ( sb , cg - > cg_boff ) ) ;
printk ( " iuseoff: %u \n " , fs32_to_cpu ( sb , cg - > cg_iusedoff ) ) ;
printk ( " freeoff: %u \n " , fs32_to_cpu ( sb , cg - > cg_freeoff ) ) ;
printk ( " nextfreeoff: %u \n " , fs32_to_cpu ( sb , cg - > cg_nextfreeoff ) ) ;
2006-06-25 16:47:29 +04:00
printk ( " clustersumoff %u \n " ,
fs32_to_cpu ( sb , cg - > cg_u . cg_44 . cg_clustersumoff ) ) ;
printk ( " clusteroff %u \n " ,
fs32_to_cpu ( sb , cg - > cg_u . cg_44 . cg_clusteroff ) ) ;
printk ( " nclusterblks %u \n " ,
fs32_to_cpu ( sb , cg - > cg_u . cg_44 . cg_nclusterblks ) ) ;
2005-04-17 02:20:36 +04:00
printk ( " \n " ) ;
}
2006-06-25 16:47:29 +04:00
# else
2007-02-12 11:54:31 +03:00
# define ufs_print_super_stuff(sb, usb1, usb2, usb3) /**/
2006-06-25 16:47:29 +04:00
# define ufs_print_cylinder_stuff(sb, cg) /**/
2006-06-25 16:47:24 +04:00
# endif /* CONFIG_UFS_DEBUG */
2005-04-17 02:20:36 +04:00
2007-02-12 11:55:41 +03:00
static const struct super_operations ufs_super_ops ;
2005-04-17 02:20:36 +04:00
static char error_buf [ 1024 ] ;
void ufs_error ( struct super_block * sb , const char * function ,
const char * fmt , . . . )
{
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
va_list args ;
uspi = UFS_SB ( sb ) - > s_uspi ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
usb1 - > fs_clean = UFS_FSBAD ;
2006-06-25 16:47:22 +04:00
ubh_mark_buffer_dirty ( USPI_UBH ( uspi ) ) ;
2012-07-12 17:28:08 +04:00
ufs_mark_sb_dirty ( sb ) ;
2005-04-17 02:20:36 +04:00
sb - > s_flags | = MS_RDONLY ;
}
va_start ( args , fmt ) ;
2006-12-07 07:37:04 +03:00
vsnprintf ( error_buf , sizeof ( error_buf ) , fmt , args ) ;
2005-04-17 02:20:36 +04:00
va_end ( args ) ;
switch ( UFS_SB ( sb ) - > s_mount_opt & UFS_MOUNT_ONERROR ) {
case UFS_MOUNT_ONERROR_PANIC :
panic ( " UFS-fs panic (device %s): %s: %s \n " ,
sb - > s_id , function , error_buf ) ;
case UFS_MOUNT_ONERROR_LOCK :
case UFS_MOUNT_ONERROR_UMOUNT :
case UFS_MOUNT_ONERROR_REPAIR :
printk ( KERN_CRIT " UFS-fs error (device %s): %s: %s \n " ,
sb - > s_id , function , error_buf ) ;
}
}
void ufs_panic ( struct super_block * sb , const char * function ,
const char * fmt , . . . )
{
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
va_list args ;
uspi = UFS_SB ( sb ) - > s_uspi ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
usb1 - > fs_clean = UFS_FSBAD ;
2006-06-25 16:47:22 +04:00
ubh_mark_buffer_dirty ( USPI_UBH ( uspi ) ) ;
2012-07-12 17:28:08 +04:00
ufs_mark_sb_dirty ( sb ) ;
2005-04-17 02:20:36 +04:00
}
va_start ( args , fmt ) ;
2006-12-07 07:37:04 +03:00
vsnprintf ( error_buf , sizeof ( error_buf ) , fmt , args ) ;
2005-04-17 02:20:36 +04:00
va_end ( args ) ;
sb - > s_flags | = MS_RDONLY ;
printk ( KERN_CRIT " UFS-fs panic (device %s): %s: %s \n " ,
sb - > s_id , function , error_buf ) ;
}
void ufs_warning ( struct super_block * sb , const char * function ,
const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
2006-12-07 07:37:04 +03:00
vsnprintf ( error_buf , sizeof ( error_buf ) , fmt , args ) ;
2005-04-17 02:20:36 +04:00
va_end ( args ) ;
printk ( KERN_WARNING " UFS-fs warning (device %s): %s: %s \n " ,
sb - > s_id , function , error_buf ) ;
}
enum {
2007-10-17 10:26:32 +04:00
Opt_type_old = UFS_MOUNT_UFSTYPE_OLD ,
Opt_type_sunx86 = UFS_MOUNT_UFSTYPE_SUNx86 ,
Opt_type_sun = UFS_MOUNT_UFSTYPE_SUN ,
Opt_type_sunos = UFS_MOUNT_UFSTYPE_SUNOS ,
Opt_type_44bsd = UFS_MOUNT_UFSTYPE_44BSD ,
Opt_type_ufs2 = UFS_MOUNT_UFSTYPE_UFS2 ,
Opt_type_hp = UFS_MOUNT_UFSTYPE_HP ,
Opt_type_nextstepcd = UFS_MOUNT_UFSTYPE_NEXTSTEP_CD ,
Opt_type_nextstep = UFS_MOUNT_UFSTYPE_NEXTSTEP ,
Opt_type_openstep = UFS_MOUNT_UFSTYPE_OPENSTEP ,
Opt_onerror_panic = UFS_MOUNT_ONERROR_PANIC ,
Opt_onerror_lock = UFS_MOUNT_ONERROR_LOCK ,
Opt_onerror_umount = UFS_MOUNT_ONERROR_UMOUNT ,
Opt_onerror_repair = UFS_MOUNT_ONERROR_REPAIR ,
Opt_err
2005-04-17 02:20:36 +04:00
} ;
2008-10-13 13:46:57 +04:00
static const match_table_t tokens = {
2005-04-17 02:20:36 +04:00
{ Opt_type_old , " ufstype=old " } ,
{ Opt_type_sunx86 , " ufstype=sunx86 " } ,
{ Opt_type_sun , " ufstype=sun " } ,
2007-10-17 10:26:31 +04:00
{ Opt_type_sunos , " ufstype=sunos " } ,
2005-04-17 02:20:36 +04:00
{ Opt_type_44bsd , " ufstype=44bsd " } ,
{ Opt_type_ufs2 , " ufstype=ufs2 " } ,
{ Opt_type_ufs2 , " ufstype=5xbsd " } ,
{ Opt_type_hp , " ufstype=hp " } ,
{ Opt_type_nextstepcd , " ufstype=nextstep-cd " } ,
{ Opt_type_nextstep , " ufstype=nextstep " } ,
{ Opt_type_openstep , " ufstype=openstep " } ,
2007-10-17 10:26:32 +04:00
/*end of possible ufs types */
2005-04-17 02:20:36 +04:00
{ Opt_onerror_panic , " onerror=panic " } ,
{ Opt_onerror_lock , " onerror=lock " } ,
{ Opt_onerror_umount , " onerror=umount " } ,
{ Opt_onerror_repair , " onerror=repair " } ,
{ Opt_err , NULL }
} ;
static int ufs_parse_options ( char * options , unsigned * mount_options )
{
char * p ;
2006-06-25 16:47:24 +04:00
UFSD ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
if ( ! options )
return 1 ;
while ( ( p = strsep ( & options , " , " ) ) ! = NULL ) {
substring_t args [ MAX_OPT_ARGS ] ;
int token ;
if ( ! * p )
continue ;
token = match_token ( p , tokens , args ) ;
switch ( token ) {
case Opt_type_old :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_OLD ) ;
break ;
case Opt_type_sunx86 :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_SUNx86 ) ;
break ;
case Opt_type_sun :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_SUN ) ;
break ;
2007-10-17 10:26:31 +04:00
case Opt_type_sunos :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_SUNOS ) ;
break ;
2005-04-17 02:20:36 +04:00
case Opt_type_44bsd :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_44BSD ) ;
break ;
case Opt_type_ufs2 :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_UFS2 ) ;
break ;
case Opt_type_hp :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_HP ) ;
break ;
case Opt_type_nextstepcd :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_NEXTSTEP_CD ) ;
break ;
case Opt_type_nextstep :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_NEXTSTEP ) ;
break ;
case Opt_type_openstep :
ufs_clear_opt ( * mount_options , UFSTYPE ) ;
ufs_set_opt ( * mount_options , UFSTYPE_OPENSTEP ) ;
break ;
case Opt_onerror_panic :
ufs_clear_opt ( * mount_options , ONERROR ) ;
ufs_set_opt ( * mount_options , ONERROR_PANIC ) ;
break ;
case Opt_onerror_lock :
ufs_clear_opt ( * mount_options , ONERROR ) ;
ufs_set_opt ( * mount_options , ONERROR_LOCK ) ;
break ;
case Opt_onerror_umount :
ufs_clear_opt ( * mount_options , ONERROR ) ;
ufs_set_opt ( * mount_options , ONERROR_UMOUNT ) ;
break ;
case Opt_onerror_repair :
printk ( " UFS-fs: Unable to do repair on error, "
" will lock lock instead \n " ) ;
ufs_clear_opt ( * mount_options , ONERROR ) ;
ufs_set_opt ( * mount_options , ONERROR_REPAIR ) ;
break ;
default :
printk ( " UFS-fs: Invalid option: \" %s \" "
" or missing value \n " , p ) ;
return 0 ;
}
}
return 1 ;
}
/*
2011-03-31 05:57:33 +04:00
* Different types of UFS hold fs_cstotal in different
* places , and use different data structure for it .
* To make things simpler we just copy fs_cstotal to ufs_sb_private_info
2005-04-17 02:20:36 +04:00
*/
2006-06-25 16:47:30 +04:00
static void ufs_setup_cstotal ( struct super_block * sb )
2006-02-03 14:04:04 +03:00
{
2006-06-25 16:47:29 +04:00
struct ufs_sb_info * sbi = UFS_SB ( sb ) ;
struct ufs_sb_private_info * uspi = sbi - > s_uspi ;
2006-06-25 16:47:30 +04:00
struct ufs_super_block_first * usb1 ;
struct ufs_super_block_second * usb2 ;
2006-06-25 16:47:29 +04:00
struct ufs_super_block_third * usb3 ;
2006-06-25 16:47:30 +04:00
unsigned mtype = sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ;
UFSD ( " ENTER, mtype=%u \n " , mtype ) ;
usb1 = ubh_get_usb_first ( uspi ) ;
usb2 = ubh_get_usb_second ( uspi ) ;
usb3 = ubh_get_usb_third ( uspi ) ;
if ( ( mtype = = UFS_MOUNT_UFSTYPE_44BSD & &
( usb1 - > fs_flags & UFS_FLAGS_UPDATED ) ) | |
mtype = = UFS_MOUNT_UFSTYPE_UFS2 ) {
/*we have statistic in different place, then usual*/
uspi - > cs_total . cs_ndir = fs64_to_cpu ( sb , usb2 - > fs_un . fs_u2 . cs_ndir ) ;
uspi - > cs_total . cs_nbfree = fs64_to_cpu ( sb , usb2 - > fs_un . fs_u2 . cs_nbfree ) ;
uspi - > cs_total . cs_nifree = fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . cs_nifree ) ;
uspi - > cs_total . cs_nffree = fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . cs_nffree ) ;
} else {
uspi - > cs_total . cs_ndir = fs32_to_cpu ( sb , usb1 - > fs_cstotal . cs_ndir ) ;
uspi - > cs_total . cs_nbfree = fs32_to_cpu ( sb , usb1 - > fs_cstotal . cs_nbfree ) ;
uspi - > cs_total . cs_nifree = fs32_to_cpu ( sb , usb1 - > fs_cstotal . cs_nifree ) ;
uspi - > cs_total . cs_nffree = fs32_to_cpu ( sb , usb1 - > fs_cstotal . cs_nffree ) ;
}
UFSD ( " EXIT \n " ) ;
}
/*
* Read on - disk structures associated with cylinder groups
*/
static int ufs_read_cylinder_structures ( struct super_block * sb )
{
struct ufs_sb_info * sbi = UFS_SB ( sb ) ;
struct ufs_sb_private_info * uspi = sbi - > s_uspi ;
2005-04-17 02:20:36 +04:00
struct ufs_buffer_head * ubh ;
unsigned char * base , * space ;
unsigned size , blks , i ;
2006-06-25 16:47:30 +04:00
struct ufs_super_block_third * usb3 ;
2006-06-25 16:47:24 +04:00
UFSD ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:30 +04:00
usb3 = ubh_get_usb_third ( uspi ) ;
2005-04-17 02:20:36 +04:00
/*
* Read cs structures from ( usually ) first data block
* on the device .
*/
size = uspi - > s_cssize ;
blks = ( size + uspi - > s_fsize - 1 ) > > uspi - > s_fshift ;
2011-01-24 12:14:12 +03:00
base = space = kmalloc ( size , GFP_NOFS ) ;
2005-04-17 02:20:36 +04:00
if ( ! base )
goto failed ;
2006-02-03 14:04:04 +03:00
sbi - > s_csp = ( struct ufs_csum * ) space ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < blks ; i + = uspi - > s_fpb ) {
size = uspi - > s_bsize ;
if ( i + uspi - > s_fpb > blks )
size = ( blks - i ) * uspi - > s_fsize ;
2007-02-12 11:54:31 +03:00
ubh = ubh_bread ( sb , uspi - > s_csaddr + i , size ) ;
2006-01-14 11:42:06 +03:00
if ( ! ubh )
goto failed ;
ubh_ubhcpymem ( space , ubh , size ) ;
2005-04-17 02:20:36 +04:00
space + = size ;
ubh_brelse ( ubh ) ;
ubh = NULL ;
}
/*
* Read cylinder group ( we read only first fragment from block
* at this time ) and prepare internal data structures for cg caching .
*/
2011-01-24 12:14:12 +03:00
if ( ! ( sbi - > s_ucg = kmalloc ( sizeof ( struct buffer_head * ) * uspi - > s_ncg , GFP_NOFS ) ) )
2005-04-17 02:20:36 +04:00
goto failed ;
for ( i = 0 ; i < uspi - > s_ncg ; i + + )
sbi - > s_ucg [ i ] = NULL ;
for ( i = 0 ; i < UFS_MAX_GROUP_LOADED ; i + + ) {
sbi - > s_ucpi [ i ] = NULL ;
sbi - > s_cgno [ i ] = UFS_CGNO_EMPTY ;
}
for ( i = 0 ; i < uspi - > s_ncg ; i + + ) {
2006-06-25 16:47:24 +04:00
UFSD ( " read cg %u \n " , i ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( sbi - > s_ucg [ i ] = sb_bread ( sb , ufs_cgcmin ( i ) ) ) )
goto failed ;
if ( ! ufs_cg_chkmagic ( sb , ( struct ufs_cylinder_group * ) sbi - > s_ucg [ i ] - > b_data ) )
goto failed ;
2006-06-25 16:47:29 +04:00
2005-04-17 02:20:36 +04:00
ufs_print_cylinder_stuff ( sb , ( struct ufs_cylinder_group * ) sbi - > s_ucg [ i ] - > b_data ) ;
}
for ( i = 0 ; i < UFS_MAX_GROUP_LOADED ; i + + ) {
2011-01-24 12:14:12 +03:00
if ( ! ( sbi - > s_ucpi [ i ] = kmalloc ( sizeof ( struct ufs_cg_private_info ) , GFP_NOFS ) ) )
2005-04-17 02:20:36 +04:00
goto failed ;
sbi - > s_cgno [ i ] = UFS_CGNO_EMPTY ;
}
sbi - > s_cg_loaded = 0 ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
failed :
2005-11-07 12:01:34 +03:00
kfree ( base ) ;
2005-04-17 02:20:36 +04:00
if ( sbi - > s_ucg ) {
for ( i = 0 ; i < uspi - > s_ncg ; i + + )
2005-11-07 12:01:34 +03:00
if ( sbi - > s_ucg [ i ] )
brelse ( sbi - > s_ucg [ i ] ) ;
2005-04-17 02:20:36 +04:00
kfree ( sbi - > s_ucg ) ;
for ( i = 0 ; i < UFS_MAX_GROUP_LOADED ; i + + )
2005-11-07 12:01:34 +03:00
kfree ( sbi - > s_ucpi [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (FAILED) \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
2006-06-25 16:47:30 +04:00
* Sync our internal copy of fs_cstotal with disk
2005-04-17 02:20:36 +04:00
*/
2006-06-25 16:47:30 +04:00
static void ufs_put_cstotal ( struct super_block * sb )
2006-02-03 14:04:04 +03:00
{
2006-06-25 16:47:30 +04:00
unsigned mtype = UFS_SB ( sb ) - > s_mount_opt & UFS_MOUNT_UFSTYPE ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_super_block_second * usb2 ;
struct ufs_super_block_third * usb3 ;
UFSD ( " ENTER \n " ) ;
usb1 = ubh_get_usb_first ( uspi ) ;
usb2 = ubh_get_usb_second ( uspi ) ;
usb3 = ubh_get_usb_third ( uspi ) ;
if ( ( mtype = = UFS_MOUNT_UFSTYPE_44BSD & &
( usb1 - > fs_flags & UFS_FLAGS_UPDATED ) ) | |
mtype = = UFS_MOUNT_UFSTYPE_UFS2 ) {
/*we have statistic in different place, then usual*/
usb2 - > fs_un . fs_u2 . cs_ndir =
cpu_to_fs64 ( sb , uspi - > cs_total . cs_ndir ) ;
usb2 - > fs_un . fs_u2 . cs_nbfree =
cpu_to_fs64 ( sb , uspi - > cs_total . cs_nbfree ) ;
usb3 - > fs_un1 . fs_u2 . cs_nifree =
cpu_to_fs64 ( sb , uspi - > cs_total . cs_nifree ) ;
usb3 - > fs_un1 . fs_u2 . cs_nffree =
cpu_to_fs64 ( sb , uspi - > cs_total . cs_nffree ) ;
} else {
usb1 - > fs_cstotal . cs_ndir =
cpu_to_fs32 ( sb , uspi - > cs_total . cs_ndir ) ;
usb1 - > fs_cstotal . cs_nbfree =
cpu_to_fs32 ( sb , uspi - > cs_total . cs_nbfree ) ;
usb1 - > fs_cstotal . cs_nifree =
cpu_to_fs32 ( sb , uspi - > cs_total . cs_nifree ) ;
usb1 - > fs_cstotal . cs_nffree =
cpu_to_fs32 ( sb , uspi - > cs_total . cs_nffree ) ;
}
ubh_mark_buffer_dirty ( USPI_UBH ( uspi ) ) ;
2007-02-12 11:54:31 +03:00
ufs_print_super_stuff ( sb , usb1 , usb2 , usb3 ) ;
2006-06-25 16:47:30 +04:00
UFSD ( " EXIT \n " ) ;
}
/**
* ufs_put_super_internal ( ) - put on - disk intrenal structures
* @ sb : pointer to super_block structure
* Put on - disk structures associated with cylinder groups
* and write them back to disk , also update cs_total on disk
*/
static void ufs_put_super_internal ( struct super_block * sb )
{
struct ufs_sb_info * sbi = UFS_SB ( sb ) ;
struct ufs_sb_private_info * uspi = sbi - > s_uspi ;
2005-04-17 02:20:36 +04:00
struct ufs_buffer_head * ubh ;
unsigned char * base , * space ;
unsigned blks , size , i ;
2006-06-25 16:47:30 +04:00
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:24 +04:00
UFSD ( " ENTER \n " ) ;
push BKL down into ->put_super
Move BKL into ->put_super from the only caller. A couple of
filesystems had trivial enough ->put_super (only kfree and NULLing of
s_fs_info + stuff in there) to not get any locking: coda, cramfs, efs,
hugetlbfs, omfs, qnx4, shmem, all others got the full treatment. Most
of them probably don't need it, but I'd rather sort that out individually.
Preferably after all the other BKL pushdowns in that area.
[AV: original used to move lock_super() down as well; these changes are
removed since we don't do lock_super() at all in generic_shutdown_super()
now]
[AV: fuse, btrfs and xfs are known to need no damn BKL, exempt]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2009-05-05 17:40:36 +04:00
2006-06-25 16:47:30 +04:00
ufs_put_cstotal ( sb ) ;
2005-04-17 02:20:36 +04:00
size = uspi - > s_cssize ;
blks = ( size + uspi - > s_fsize - 1 ) > > uspi - > s_fshift ;
2006-02-03 14:04:04 +03:00
base = space = ( char * ) sbi - > s_csp ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < blks ; i + = uspi - > s_fpb ) {
size = uspi - > s_bsize ;
if ( i + uspi - > s_fpb > blks )
size = ( blks - i ) * uspi - > s_fsize ;
2007-02-12 11:54:31 +03:00
2005-04-17 02:20:36 +04:00
ubh = ubh_bread ( sb , uspi - > s_csaddr + i , size ) ;
2007-02-12 11:54:31 +03:00
2005-04-17 02:20:36 +04:00
ubh_memcpyubh ( ubh , space , size ) ;
space + = size ;
ubh_mark_buffer_uptodate ( ubh , 1 ) ;
ubh_mark_buffer_dirty ( ubh ) ;
ubh_brelse ( ubh ) ;
}
for ( i = 0 ; i < sbi - > s_cg_loaded ; i + + ) {
ufs_put_cylinder ( sb , i ) ;
kfree ( sbi - > s_ucpi [ i ] ) ;
}
for ( ; i < UFS_MAX_GROUP_LOADED ; i + + )
kfree ( sbi - > s_ucpi [ i ] ) ;
for ( i = 0 ; i < uspi - > s_ncg ; i + + )
brelse ( sbi - > s_ucg [ i ] ) ;
kfree ( sbi - > s_ucg ) ;
kfree ( base ) ;
push BKL down into ->put_super
Move BKL into ->put_super from the only caller. A couple of
filesystems had trivial enough ->put_super (only kfree and NULLing of
s_fs_info + stuff in there) to not get any locking: coda, cramfs, efs,
hugetlbfs, omfs, qnx4, shmem, all others got the full treatment. Most
of them probably don't need it, but I'd rather sort that out individually.
Preferably after all the other BKL pushdowns in that area.
[AV: original used to move lock_super() down as well; these changes are
removed since we don't do lock_super() at all in generic_shutdown_super()
now]
[AV: fuse, btrfs and xfs are known to need no damn BKL, exempt]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2009-05-05 17:40:36 +04:00
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
2012-07-12 17:28:07 +04:00
static int ufs_sync_fs ( struct super_block * sb , int wait )
{
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_super_block_third * usb3 ;
unsigned flags ;
lock_ufs ( sb ) ;
lock_super ( sb ) ;
UFSD ( " ENTER \n " ) ;
flags = UFS_SB ( sb ) - > s_flags ;
uspi = UFS_SB ( sb ) - > s_uspi ;
usb1 = ubh_get_usb_first ( uspi ) ;
usb3 = ubh_get_usb_third ( uspi ) ;
usb1 - > fs_time = cpu_to_fs32 ( sb , get_seconds ( ) ) ;
if ( ( flags & UFS_ST_MASK ) = = UFS_ST_SUN | |
( flags & UFS_ST_MASK ) = = UFS_ST_SUNOS | |
( flags & UFS_ST_MASK ) = = UFS_ST_SUNx86 )
ufs_set_fs_state ( sb , usb1 , usb3 ,
UFS_FSOK - fs32_to_cpu ( sb , usb1 - > fs_time ) ) ;
ufs_put_cstotal ( sb ) ;
UFSD ( " EXIT \n " ) ;
unlock_super ( sb ) ;
unlock_ufs ( sb ) ;
return 0 ;
}
2012-07-12 17:28:08 +04:00
static void delayed_sync_fs ( struct work_struct * work )
2012-07-12 17:28:07 +04:00
{
2012-07-12 17:28:08 +04:00
struct ufs_sb_info * sbi ;
sbi = container_of ( work , struct ufs_sb_info , sync_work . work ) ;
spin_lock ( & sbi - > work_lock ) ;
sbi - > work_queued = 0 ;
spin_unlock ( & sbi - > work_lock ) ;
ufs_sync_fs ( sbi - > sb , 1 ) ;
}
void ufs_mark_sb_dirty ( struct super_block * sb )
{
struct ufs_sb_info * sbi = UFS_SB ( sb ) ;
unsigned long delay ;
spin_lock ( & sbi - > work_lock ) ;
if ( ! sbi - > work_queued ) {
delay = msecs_to_jiffies ( dirty_writeback_interval * 10 ) ;
queue_delayed_work ( system_long_wq , & sbi - > sync_work , delay ) ;
sbi - > work_queued = 1 ;
}
spin_unlock ( & sbi - > work_lock ) ;
2012-07-12 17:28:07 +04:00
}
static void ufs_put_super ( struct super_block * sb )
{
struct ufs_sb_info * sbi = UFS_SB ( sb ) ;
UFSD ( " ENTER \n " ) ;
if ( ! ( sb - > s_flags & MS_RDONLY ) )
ufs_put_super_internal ( sb ) ;
2012-07-12 17:28:08 +04:00
cancel_delayed_work_sync ( & sbi - > sync_work ) ;
2012-07-12 17:28:07 +04:00
ubh_brelse_uspi ( sbi - > s_uspi ) ;
kfree ( sbi - > s_uspi ) ;
kfree ( sbi ) ;
sb - > s_fs_info = NULL ;
UFSD ( " EXIT \n " ) ;
return ;
}
2005-04-17 02:20:36 +04:00
static int ufs_fill_super ( struct super_block * sb , void * data , int silent )
{
struct ufs_sb_info * sbi ;
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_super_block_second * usb2 ;
struct ufs_super_block_third * usb3 ;
struct ufs_buffer_head * ubh ;
struct inode * inode ;
unsigned block_size , super_block_size ;
unsigned flags ;
2006-01-14 11:42:06 +03:00
unsigned super_block_offset ;
2009-01-09 01:43:48 +03:00
unsigned maxsymlen ;
2008-02-07 11:15:48 +03:00
int ret = - EINVAL ;
2005-04-17 02:20:36 +04:00
uspi = NULL ;
ubh = NULL ;
flags = 0 ;
2006-06-25 16:47:24 +04:00
UFSD ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2006-09-27 12:49:37 +04:00
sbi = kzalloc ( sizeof ( struct ufs_sb_info ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! sbi )
goto failed_nomem ;
sb - > s_fs_info = sbi ;
2012-07-12 17:28:08 +04:00
sbi - > sb = sb ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:24 +04:00
UFSD ( " flag %u \n " , ( int ) ( sb - > s_flags & MS_RDONLY ) ) ;
2005-04-17 02:20:36 +04:00
# ifndef CONFIG_UFS_FS_WRITE
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
printk ( " ufs was compiled with read-only support, "
" can't be mounted as read-write \n " ) ;
goto failed ;
}
# endif
2011-01-24 12:14:12 +03:00
mutex_init ( & sbi - > mutex ) ;
2012-07-12 17:28:08 +04:00
spin_lock_init ( & sbi - > work_lock ) ;
INIT_DELAYED_WORK ( & sbi - > sync_work , delayed_sync_fs ) ;
2005-04-17 02:20:36 +04:00
/*
* Set default mount options
* Parse mount options
*/
sbi - > s_mount_opt = 0 ;
ufs_set_opt ( sbi - > s_mount_opt , ONERROR_LOCK ) ;
if ( ! ufs_parse_options ( ( char * ) data , & sbi - > s_mount_opt ) ) {
printk ( " wrong mount options \n " ) ;
goto failed ;
}
if ( ! ( sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ) ) {
if ( ! silent )
printk ( " You didn't specify the type of your ufs filesystem \n \n "
" mount -t ufs -o ufstype= "
2006-03-24 20:21:44 +03:00
" sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|nextstep-cd|openstep ... \n \n "
2005-04-17 02:20:36 +04:00
" >>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
" default is ufstype=old \n " ) ;
ufs_set_opt ( sbi - > s_mount_opt , UFSTYPE_OLD ) ;
}
2007-10-17 10:26:31 +04:00
uspi = kzalloc ( sizeof ( struct ufs_sb_private_info ) , GFP_KERNEL ) ;
sbi - > s_uspi = uspi ;
2005-04-17 02:20:36 +04:00
if ( ! uspi )
goto failed ;
2007-02-09 01:20:25 +03:00
uspi - > s_dirblksize = UFS_SECTOR_SIZE ;
2006-01-14 11:42:06 +03:00
super_block_offset = UFS_SBLOCK ;
2005-04-17 02:20:36 +04:00
/* Keep 2Gig file limit. Some UFS variants need to override
this but as I don ' t know which I ' ll let those in the know loosen
the rules */
switch ( sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ) {
case UFS_MOUNT_UFSTYPE_44BSD :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=44bsd \n " ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 512 ;
uspi - > s_fmask = ~ ( 512 - 1 ) ;
uspi - > s_fshift = 9 ;
uspi - > s_sbsize = super_block_size = 1536 ;
uspi - > s_sbbase = 0 ;
flags | = UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD ;
break ;
case UFS_MOUNT_UFSTYPE_UFS2 :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=ufs2 \n " ) ;
2006-01-14 11:42:06 +03:00
super_block_offset = SBLOCK_UFS2 ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 512 ;
uspi - > s_fmask = ~ ( 512 - 1 ) ;
uspi - > s_fshift = 9 ;
uspi - > s_sbsize = super_block_size = 1536 ;
uspi - > s_sbbase = 0 ;
flags | = UFS_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD ;
break ;
case UFS_MOUNT_UFSTYPE_SUN :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=sun \n " ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 1024 ;
uspi - > s_fmask = ~ ( 1024 - 1 ) ;
uspi - > s_fshift = 10 ;
uspi - > s_sbsize = super_block_size = 2048 ;
uspi - > s_sbbase = 0 ;
2007-10-17 10:26:31 +04:00
uspi - > s_maxsymlinklen = 0 ; /* Not supported on disk */
2005-04-17 02:20:36 +04:00
flags | = UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN ;
break ;
2007-10-17 10:26:31 +04:00
case UFS_MOUNT_UFSTYPE_SUNOS :
UFSD ( ( " ufstype=sunos \n " ) )
uspi - > s_fsize = block_size = 1024 ;
uspi - > s_fmask = ~ ( 1024 - 1 ) ;
uspi - > s_fshift = 10 ;
uspi - > s_sbsize = 2048 ;
super_block_size = 2048 ;
uspi - > s_sbbase = 0 ;
uspi - > s_maxsymlinklen = 0 ; /* Not supported on disk */
flags | = UFS_DE_OLD | UFS_UID_OLD | UFS_ST_SUNOS | UFS_CG_SUN ;
break ;
2005-04-17 02:20:36 +04:00
case UFS_MOUNT_UFSTYPE_SUNx86 :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=sunx86 \n " ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 1024 ;
uspi - > s_fmask = ~ ( 1024 - 1 ) ;
uspi - > s_fshift = 10 ;
uspi - > s_sbsize = super_block_size = 2048 ;
uspi - > s_sbbase = 0 ;
2007-10-17 10:26:31 +04:00
uspi - > s_maxsymlinklen = 0 ; /* Not supported on disk */
2005-04-17 02:20:36 +04:00
flags | = UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN ;
break ;
case UFS_MOUNT_UFSTYPE_OLD :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=old \n " ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 1024 ;
uspi - > s_fmask = ~ ( 1024 - 1 ) ;
uspi - > s_fshift = 10 ;
uspi - > s_sbsize = super_block_size = 2048 ;
uspi - > s_sbbase = 0 ;
flags | = UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD ;
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
if ( ! silent )
printk ( KERN_INFO " ufstype=old is supported read-only \n " ) ;
sb - > s_flags | = MS_RDONLY ;
}
break ;
case UFS_MOUNT_UFSTYPE_NEXTSTEP :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=nextstep \n " ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 1024 ;
uspi - > s_fmask = ~ ( 1024 - 1 ) ;
uspi - > s_fshift = 10 ;
uspi - > s_sbsize = super_block_size = 2048 ;
uspi - > s_sbbase = 0 ;
2007-12-05 10:45:06 +03:00
uspi - > s_dirblksize = 1024 ;
2005-04-17 02:20:36 +04:00
flags | = UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD ;
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
if ( ! silent )
printk ( KERN_INFO " ufstype=nextstep is supported read-only \n " ) ;
sb - > s_flags | = MS_RDONLY ;
}
break ;
case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=nextstep-cd \n " ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 2048 ;
uspi - > s_fmask = ~ ( 2048 - 1 ) ;
uspi - > s_fshift = 11 ;
uspi - > s_sbsize = super_block_size = 2048 ;
uspi - > s_sbbase = 0 ;
2007-12-05 10:45:06 +03:00
uspi - > s_dirblksize = 1024 ;
2005-04-17 02:20:36 +04:00
flags | = UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD ;
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
if ( ! silent )
printk ( KERN_INFO " ufstype=nextstep-cd is supported read-only \n " ) ;
sb - > s_flags | = MS_RDONLY ;
}
break ;
case UFS_MOUNT_UFSTYPE_OPENSTEP :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=openstep \n " ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 1024 ;
uspi - > s_fmask = ~ ( 1024 - 1 ) ;
uspi - > s_fshift = 10 ;
uspi - > s_sbsize = super_block_size = 2048 ;
uspi - > s_sbbase = 0 ;
2007-02-09 01:20:25 +03:00
uspi - > s_dirblksize = 1024 ;
2005-04-17 02:20:36 +04:00
flags | = UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD ;
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
if ( ! silent )
printk ( KERN_INFO " ufstype=openstep is supported read-only \n " ) ;
sb - > s_flags | = MS_RDONLY ;
}
break ;
case UFS_MOUNT_UFSTYPE_HP :
2006-06-25 16:47:24 +04:00
UFSD ( " ufstype=hp \n " ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fsize = block_size = 1024 ;
uspi - > s_fmask = ~ ( 1024 - 1 ) ;
uspi - > s_fshift = 10 ;
uspi - > s_sbsize = super_block_size = 2048 ;
uspi - > s_sbbase = 0 ;
flags | = UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD ;
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
if ( ! silent )
printk ( KERN_INFO " ufstype=hp is supported read-only \n " ) ;
sb - > s_flags | = MS_RDONLY ;
}
break ;
default :
if ( ! silent )
printk ( " unknown ufstype \n " ) ;
goto failed ;
}
again :
if ( ! sb_set_blocksize ( sb , block_size ) ) {
printk ( KERN_ERR " UFS: failed to set blocksize \n " ) ;
goto failed ;
}
/*
* read ufs super block from device
*/
2006-01-14 11:42:06 +03:00
ubh = ubh_bread_uspi ( uspi , sb , uspi - > s_sbbase + super_block_offset / block_size , super_block_size ) ;
2005-04-17 02:20:36 +04:00
if ( ! ubh )
goto failed ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
usb2 = ubh_get_usb_second ( uspi ) ;
usb3 = ubh_get_usb_third ( uspi ) ;
2005-04-17 02:20:36 +04:00
2007-10-17 10:26:31 +04:00
/* Sort out mod used on SunOS 4.1.3 for fs_state */
uspi - > s_postblformat = fs32_to_cpu ( sb , usb3 - > fs_postblformat ) ;
if ( ( ( flags & UFS_ST_MASK ) = = UFS_ST_SUNOS ) & &
( uspi - > s_postblformat ! = UFS_42POSTBLFMT ) ) {
flags & = ~ UFS_ST_MASK ;
flags | = UFS_ST_SUN ;
}
2005-04-17 02:20:36 +04:00
/*
* Check ufs magic number
*/
sbi - > s_bytesex = BYTESEX_LE ;
switch ( ( uspi - > fs_magic = fs32_to_cpu ( sb , usb3 - > fs_magic ) ) ) {
case UFS_MAGIC :
2010-05-27 01:42:33 +04:00
case UFS_MAGIC_BW :
2005-04-17 02:20:36 +04:00
case UFS2_MAGIC :
case UFS_MAGIC_LFN :
case UFS_MAGIC_FEA :
case UFS_MAGIC_4GB :
goto magic_found ;
}
sbi - > s_bytesex = BYTESEX_BE ;
switch ( ( uspi - > fs_magic = fs32_to_cpu ( sb , usb3 - > fs_magic ) ) ) {
case UFS_MAGIC :
2010-05-27 01:42:33 +04:00
case UFS_MAGIC_BW :
2005-04-17 02:20:36 +04:00
case UFS2_MAGIC :
case UFS_MAGIC_LFN :
case UFS_MAGIC_FEA :
case UFS_MAGIC_4GB :
goto magic_found ;
}
if ( ( ( ( sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ) = = UFS_MOUNT_UFSTYPE_NEXTSTEP )
| | ( ( sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ) = = UFS_MOUNT_UFSTYPE_NEXTSTEP_CD )
| | ( ( sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ) = = UFS_MOUNT_UFSTYPE_OPENSTEP ) )
& & uspi - > s_sbbase < 256 ) {
ubh_brelse_uspi ( uspi ) ;
ubh = NULL ;
uspi - > s_sbbase + = 8 ;
goto again ;
}
if ( ! silent )
printk ( " ufs_read_super: bad magic number \n " ) ;
goto failed ;
magic_found :
/*
* Check block and fragment sizes
*/
uspi - > s_bsize = fs32_to_cpu ( sb , usb1 - > fs_bsize ) ;
uspi - > s_fsize = fs32_to_cpu ( sb , usb1 - > fs_fsize ) ;
uspi - > s_sbsize = fs32_to_cpu ( sb , usb1 - > fs_sbsize ) ;
uspi - > s_fmask = fs32_to_cpu ( sb , usb1 - > fs_fmask ) ;
uspi - > s_fshift = fs32_to_cpu ( sb , usb1 - > fs_fshift ) ;
2007-07-16 10:41:36 +04:00
if ( ! is_power_of_2 ( uspi - > s_fsize ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " ufs_read_super: fragment size %u is not a power of 2 \n " ,
uspi - > s_fsize ) ;
goto failed ;
}
if ( uspi - > s_fsize < 512 ) {
printk ( KERN_ERR " ufs_read_super: fragment size %u is too small \n " ,
uspi - > s_fsize ) ;
goto failed ;
}
if ( uspi - > s_fsize > 4096 ) {
printk ( KERN_ERR " ufs_read_super: fragment size %u is too large \n " ,
uspi - > s_fsize ) ;
goto failed ;
}
2007-07-16 10:41:36 +04:00
if ( ! is_power_of_2 ( uspi - > s_bsize ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " ufs_read_super: block size %u is not a power of 2 \n " ,
uspi - > s_bsize ) ;
goto failed ;
}
if ( uspi - > s_bsize < 4096 ) {
printk ( KERN_ERR " ufs_read_super: block size %u is too small \n " ,
uspi - > s_bsize ) ;
goto failed ;
}
if ( uspi - > s_bsize / uspi - > s_fsize > 8 ) {
printk ( KERN_ERR " ufs_read_super: too many fragments per block (%u) \n " ,
uspi - > s_bsize / uspi - > s_fsize ) ;
goto failed ;
}
if ( uspi - > s_fsize ! = block_size | | uspi - > s_sbsize ! = super_block_size ) {
ubh_brelse_uspi ( uspi ) ;
ubh = NULL ;
block_size = uspi - > s_fsize ;
super_block_size = uspi - > s_sbsize ;
2006-06-25 16:47:24 +04:00
UFSD ( " another value of block_size or super_block_size %u, %u \n " , block_size , super_block_size ) ;
2005-04-17 02:20:36 +04:00
goto again ;
}
2007-10-30 00:37:21 +03:00
sbi - > s_flags = flags ; /*after that line some functions use s_flags*/
2007-02-12 11:54:31 +03:00
ufs_print_super_stuff ( sb , usb1 , usb2 , usb3 ) ;
2005-04-17 02:20:36 +04:00
/*
* Check , if file system was correctly unmounted .
* If not , make it read only .
*/
2007-10-30 00:37:21 +03:00
if ( ( ( flags & UFS_ST_MASK ) = = UFS_ST_44BSD ) | |
( ( flags & UFS_ST_MASK ) = = UFS_ST_OLD ) | |
( ( ( flags & UFS_ST_MASK ) = = UFS_ST_SUN | |
( flags & UFS_ST_MASK ) = = UFS_ST_SUNOS | |
( flags & UFS_ST_MASK ) = = UFS_ST_SUNx86 ) & &
( ufs_get_fs_state ( sb , usb1 , usb3 ) = = ( UFS_FSOK - fs32_to_cpu ( sb , usb1 - > fs_time ) ) ) ) ) {
2005-04-17 02:20:36 +04:00
switch ( usb1 - > fs_clean ) {
case UFS_FSCLEAN :
2006-06-25 16:47:24 +04:00
UFSD ( " fs is clean \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case UFS_FSSTABLE :
2006-06-25 16:47:24 +04:00
UFSD ( " fs is stable \n " ) ;
2010-03-11 02:21:53 +03:00
break ;
case UFS_FSLOG :
UFSD ( " fs is logging fs \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case UFS_FSOSF1 :
2006-06-25 16:47:24 +04:00
UFSD ( " fs is DEC OSF/1 \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case UFS_FSACTIVE :
printk ( " ufs_read_super: fs is active \n " ) ;
sb - > s_flags | = MS_RDONLY ;
break ;
case UFS_FSBAD :
printk ( " ufs_read_super: fs is bad \n " ) ;
sb - > s_flags | = MS_RDONLY ;
break ;
default :
printk ( " ufs_read_super: can't grok fs_clean 0x%x \n " , usb1 - > fs_clean ) ;
sb - > s_flags | = MS_RDONLY ;
break ;
}
2006-06-25 16:47:30 +04:00
} else {
2005-04-17 02:20:36 +04:00
printk ( " ufs_read_super: fs needs fsck \n " ) ;
sb - > s_flags | = MS_RDONLY ;
}
/*
* Read ufs_super_block into internal data structures
*/
sb - > s_op = & ufs_super_ops ;
2009-12-16 03:46:51 +03:00
sb - > s_export_op = & ufs_export_ops ;
2010-05-19 15:16:44 +04:00
2005-04-17 02:20:36 +04:00
sb - > s_magic = fs32_to_cpu ( sb , usb3 - > fs_magic ) ;
uspi - > s_sblkno = fs32_to_cpu ( sb , usb1 - > fs_sblkno ) ;
uspi - > s_cblkno = fs32_to_cpu ( sb , usb1 - > fs_cblkno ) ;
uspi - > s_iblkno = fs32_to_cpu ( sb , usb1 - > fs_iblkno ) ;
uspi - > s_dblkno = fs32_to_cpu ( sb , usb1 - > fs_dblkno ) ;
uspi - > s_cgoffset = fs32_to_cpu ( sb , usb1 - > fs_cgoffset ) ;
uspi - > s_cgmask = fs32_to_cpu ( sb , usb1 - > fs_cgmask ) ;
if ( ( flags & UFS_TYPE_MASK ) = = UFS_TYPE_UFS2 ) {
2006-06-25 16:47:29 +04:00
uspi - > s_u2_size = fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . fs_size ) ;
uspi - > s_u2_dsize = fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . fs_dsize ) ;
} else {
2005-04-17 02:20:36 +04:00
uspi - > s_size = fs32_to_cpu ( sb , usb1 - > fs_size ) ;
uspi - > s_dsize = fs32_to_cpu ( sb , usb1 - > fs_dsize ) ;
}
uspi - > s_ncg = fs32_to_cpu ( sb , usb1 - > fs_ncg ) ;
/* s_bsize already set */
/* s_fsize already set */
uspi - > s_fpb = fs32_to_cpu ( sb , usb1 - > fs_frag ) ;
uspi - > s_minfree = fs32_to_cpu ( sb , usb1 - > fs_minfree ) ;
uspi - > s_bmask = fs32_to_cpu ( sb , usb1 - > fs_bmask ) ;
uspi - > s_fmask = fs32_to_cpu ( sb , usb1 - > fs_fmask ) ;
uspi - > s_bshift = fs32_to_cpu ( sb , usb1 - > fs_bshift ) ;
uspi - > s_fshift = fs32_to_cpu ( sb , usb1 - > fs_fshift ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " uspi->s_bshift = %d,uspi->s_fshift = %d " , uspi - > s_bshift ,
uspi - > s_fshift ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_fpbshift = fs32_to_cpu ( sb , usb1 - > fs_fragshift ) ;
uspi - > s_fsbtodb = fs32_to_cpu ( sb , usb1 - > fs_fsbtodb ) ;
/* s_sbsize already set */
uspi - > s_csmask = fs32_to_cpu ( sb , usb1 - > fs_csmask ) ;
uspi - > s_csshift = fs32_to_cpu ( sb , usb1 - > fs_csshift ) ;
uspi - > s_nindir = fs32_to_cpu ( sb , usb1 - > fs_nindir ) ;
uspi - > s_inopb = fs32_to_cpu ( sb , usb1 - > fs_inopb ) ;
uspi - > s_nspf = fs32_to_cpu ( sb , usb1 - > fs_nspf ) ;
uspi - > s_npsect = ufs_get_fs_npsect ( sb , usb1 , usb3 ) ;
uspi - > s_interleave = fs32_to_cpu ( sb , usb1 - > fs_interleave ) ;
uspi - > s_trackskew = fs32_to_cpu ( sb , usb1 - > fs_trackskew ) ;
2007-02-12 11:54:31 +03:00
if ( uspi - > fs_magic = = UFS2_MAGIC )
uspi - > s_csaddr = fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . fs_csaddr ) ;
else
uspi - > s_csaddr = fs32_to_cpu ( sb , usb1 - > fs_csaddr ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_cssize = fs32_to_cpu ( sb , usb1 - > fs_cssize ) ;
uspi - > s_cgsize = fs32_to_cpu ( sb , usb1 - > fs_cgsize ) ;
uspi - > s_ntrak = fs32_to_cpu ( sb , usb1 - > fs_ntrak ) ;
uspi - > s_nsect = fs32_to_cpu ( sb , usb1 - > fs_nsect ) ;
uspi - > s_spc = fs32_to_cpu ( sb , usb1 - > fs_spc ) ;
uspi - > s_ipg = fs32_to_cpu ( sb , usb1 - > fs_ipg ) ;
uspi - > s_fpg = fs32_to_cpu ( sb , usb1 - > fs_fpg ) ;
2006-06-25 16:47:29 +04:00
uspi - > s_cpc = fs32_to_cpu ( sb , usb2 - > fs_un . fs_u1 . fs_cpc ) ;
uspi - > s_contigsumsize = fs32_to_cpu ( sb , usb3 - > fs_un2 . fs_44 . fs_contigsumsize ) ;
2005-04-17 02:20:36 +04:00
uspi - > s_qbmask = ufs_get_fs_qbmask ( sb , usb3 ) ;
uspi - > s_qfmask = ufs_get_fs_qfmask ( sb , usb3 ) ;
uspi - > s_nrpos = fs32_to_cpu ( sb , usb3 - > fs_nrpos ) ;
uspi - > s_postbloff = fs32_to_cpu ( sb , usb3 - > fs_postbloff ) ;
uspi - > s_rotbloff = fs32_to_cpu ( sb , usb3 - > fs_rotbloff ) ;
/*
* Compute another frequently used values
*/
uspi - > s_fpbmask = uspi - > s_fpb - 1 ;
2006-06-25 16:47:24 +04:00
if ( ( flags & UFS_TYPE_MASK ) = = UFS_TYPE_UFS2 )
2005-04-17 02:20:36 +04:00
uspi - > s_apbshift = uspi - > s_bshift - 3 ;
2006-06-25 16:47:24 +04:00
else
2005-04-17 02:20:36 +04:00
uspi - > s_apbshift = uspi - > s_bshift - 2 ;
2006-06-25 16:47:24 +04:00
2005-04-17 02:20:36 +04:00
uspi - > s_2apbshift = uspi - > s_apbshift * 2 ;
uspi - > s_3apbshift = uspi - > s_apbshift * 3 ;
uspi - > s_apb = 1 < < uspi - > s_apbshift ;
uspi - > s_2apb = 1 < < uspi - > s_2apbshift ;
uspi - > s_3apb = 1 < < uspi - > s_3apbshift ;
uspi - > s_apbmask = uspi - > s_apb - 1 ;
uspi - > s_nspfshift = uspi - > s_fshift - UFS_SECTOR_BITS ;
uspi - > s_nspb = uspi - > s_nspf < < uspi - > s_fpbshift ;
uspi - > s_inopf = uspi - > s_inopb > > uspi - > s_fpbshift ;
uspi - > s_bpf = uspi - > s_fsize < < 3 ;
uspi - > s_bpfshift = uspi - > s_fshift + 3 ;
uspi - > s_bpfmask = uspi - > s_bpf - 1 ;
2008-02-08 15:20:16 +03:00
if ( ( sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ) = = UFS_MOUNT_UFSTYPE_44BSD | |
( sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ) = = UFS_MOUNT_UFSTYPE_UFS2 )
2005-04-17 02:20:36 +04:00
uspi - > s_maxsymlinklen =
2006-06-25 16:47:29 +04:00
fs32_to_cpu ( sb , usb3 - > fs_un2 . fs_44 . fs_maxsymlinklen ) ;
2005-04-17 02:20:36 +04:00
2009-01-09 01:43:48 +03:00
if ( uspi - > fs_magic = = UFS2_MAGIC )
maxsymlen = 2 * 4 * ( UFS_NDADDR + UFS_NINDIR ) ;
else
maxsymlen = 4 * ( UFS_NDADDR + UFS_NINDIR ) ;
if ( uspi - > s_maxsymlinklen > maxsymlen ) {
ufs_warning ( sb , __func__ , " ufs_read_super: excessive maximum "
" fast symlink size (%u) \n " , uspi - > s_maxsymlinklen ) ;
uspi - > s_maxsymlinklen = maxsymlen ;
}
2012-02-06 21:45:27 +04:00
sb - > s_max_links = UFS_LINK_MAX ;
2009-01-09 01:43:48 +03:00
2008-02-07 11:15:48 +03:00
inode = ufs_iget ( sb , UFS_ROOTINO ) ;
if ( IS_ERR ( inode ) ) {
ret = PTR_ERR ( inode ) ;
2005-04-17 02:20:36 +04:00
goto failed ;
2008-02-07 11:15:48 +03:00
}
2012-01-09 07:15:13 +04:00
sb - > s_root = d_make_root ( inode ) ;
2008-02-07 11:15:48 +03:00
if ( ! sb - > s_root ) {
ret = - ENOMEM ;
2012-01-09 07:15:13 +04:00
goto failed ;
2008-02-07 11:15:48 +03:00
}
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:30 +04:00
ufs_setup_cstotal ( sb ) ;
2005-04-17 02:20:36 +04:00
/*
* Read cylinder group structures
*/
if ( ! ( sb - > s_flags & MS_RDONLY ) )
if ( ! ufs_read_cylinder_structures ( sb ) )
goto failed ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
failed :
2005-11-07 12:01:34 +03:00
if ( ubh )
ubh_brelse_uspi ( uspi ) ;
kfree ( uspi ) ;
kfree ( sbi ) ;
2005-04-17 02:20:36 +04:00
sb - > s_fs_info = NULL ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (FAILED) \n " ) ;
2008-02-07 11:15:48 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
failed_nomem :
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (NOMEM) \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
static int ufs_remount ( struct super_block * sb , int * mount_flags , char * data )
{
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_super_block_third * usb3 ;
unsigned new_mount_opt , ufstype ;
unsigned flags ;
2009-05-12 17:10:54 +04:00
2011-01-24 12:14:12 +03:00
lock_ufs ( sb ) ;
2009-05-06 18:43:07 +04:00
lock_super ( sb ) ;
2005-04-17 02:20:36 +04:00
uspi = UFS_SB ( sb ) - > s_uspi ;
flags = UFS_SB ( sb ) - > s_flags ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
usb3 = ubh_get_usb_third ( uspi ) ;
2005-04-17 02:20:36 +04:00
/*
* Allow the " check " option to be passed as a remount option .
* It is not possible to change ufstype option during remount
*/
ufstype = UFS_SB ( sb ) - > s_mount_opt & UFS_MOUNT_UFSTYPE ;
new_mount_opt = 0 ;
ufs_set_opt ( new_mount_opt , ONERROR_LOCK ) ;
2009-05-06 18:43:07 +04:00
if ( ! ufs_parse_options ( data , & new_mount_opt ) ) {
unlock_super ( sb ) ;
2011-01-24 12:14:12 +03:00
unlock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2009-05-06 18:43:07 +04:00
}
2005-04-17 02:20:36 +04:00
if ( ! ( new_mount_opt & UFS_MOUNT_UFSTYPE ) ) {
new_mount_opt | = ufstype ;
2006-06-25 16:47:30 +04:00
} else if ( ( new_mount_opt & UFS_MOUNT_UFSTYPE ) ! = ufstype ) {
2005-04-17 02:20:36 +04:00
printk ( " ufstype can't be changed during remount \n " ) ;
2009-05-06 18:43:07 +04:00
unlock_super ( sb ) ;
2011-01-24 12:14:12 +03:00
unlock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
if ( ( * mount_flags & MS_RDONLY ) = = ( sb - > s_flags & MS_RDONLY ) ) {
UFS_SB ( sb ) - > s_mount_opt = new_mount_opt ;
2009-05-06 18:43:07 +04:00
unlock_super ( sb ) ;
2011-01-24 12:14:12 +03:00
unlock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* fs was mouted as rw , remounting ro
*/
if ( * mount_flags & MS_RDONLY ) {
2006-06-25 16:47:30 +04:00
ufs_put_super_internal ( sb ) ;
2005-04-17 02:20:36 +04:00
usb1 - > fs_time = cpu_to_fs32 ( sb , get_seconds ( ) ) ;
if ( ( flags & UFS_ST_MASK ) = = UFS_ST_SUN
2007-10-17 10:26:31 +04:00
| | ( flags & UFS_ST_MASK ) = = UFS_ST_SUNOS
2005-04-17 02:20:36 +04:00
| | ( flags & UFS_ST_MASK ) = = UFS_ST_SUNx86 )
ufs_set_fs_state ( sb , usb1 , usb3 ,
UFS_FSOK - fs32_to_cpu ( sb , usb1 - > fs_time ) ) ;
2006-06-25 16:47:22 +04:00
ubh_mark_buffer_dirty ( USPI_UBH ( uspi ) ) ;
2005-04-17 02:20:36 +04:00
sb - > s_flags | = MS_RDONLY ;
2006-06-25 16:47:30 +04:00
} else {
2005-04-17 02:20:36 +04:00
/*
* fs was mounted as ro , remounting rw
*/
# ifndef CONFIG_UFS_FS_WRITE
printk ( " ufs was compiled with read-only support, "
" can't be mounted as read-write \n " ) ;
2009-05-06 18:43:07 +04:00
unlock_super ( sb ) ;
2011-01-24 12:14:12 +03:00
unlock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
# else
if ( ufstype ! = UFS_MOUNT_UFSTYPE_SUN & &
2007-10-17 10:26:31 +04:00
ufstype ! = UFS_MOUNT_UFSTYPE_SUNOS & &
2005-04-17 02:20:36 +04:00
ufstype ! = UFS_MOUNT_UFSTYPE_44BSD & &
2007-02-12 11:54:30 +03:00
ufstype ! = UFS_MOUNT_UFSTYPE_SUNx86 & &
ufstype ! = UFS_MOUNT_UFSTYPE_UFS2 ) {
2005-04-17 02:20:36 +04:00
printk ( " this ufstype is read-only supported \n " ) ;
2009-05-06 18:43:07 +04:00
unlock_super ( sb ) ;
2011-01-24 12:14:12 +03:00
unlock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2006-06-25 16:47:30 +04:00
if ( ! ufs_read_cylinder_structures ( sb ) ) {
2005-04-17 02:20:36 +04:00
printk ( " failed during remounting \n " ) ;
2009-05-06 18:43:07 +04:00
unlock_super ( sb ) ;
2011-01-24 12:14:12 +03:00
unlock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
return - EPERM ;
}
sb - > s_flags & = ~ MS_RDONLY ;
# endif
}
UFS_SB ( sb ) - > s_mount_opt = new_mount_opt ;
2009-05-06 18:43:07 +04:00
unlock_super ( sb ) ;
2011-01-24 12:14:12 +03:00
unlock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-12-09 06:32:45 +04:00
static int ufs_show_options ( struct seq_file * seq , struct dentry * root )
2007-10-17 10:26:32 +04:00
{
2011-12-09 06:32:45 +04:00
struct ufs_sb_info * sbi = UFS_SB ( root - > d_sb ) ;
2007-10-17 10:26:32 +04:00
unsigned mval = sbi - > s_mount_opt & UFS_MOUNT_UFSTYPE ;
2008-10-13 13:46:57 +04:00
const struct match_token * tp = tokens ;
2007-10-17 10:26:32 +04:00
while ( tp - > token ! = Opt_onerror_panic & & tp - > token ! = mval )
+ + tp ;
BUG_ON ( tp - > token = = Opt_onerror_panic ) ;
seq_printf ( seq , " ,%s " , tp - > pattern ) ;
mval = sbi - > s_mount_opt & UFS_MOUNT_ONERROR ;
while ( tp - > token ! = Opt_err & & tp - > token ! = mval )
+ + tp ;
BUG_ON ( tp - > token = = Opt_err ) ;
seq_printf ( seq , " ,%s " , tp - > pattern ) ;
return 0 ;
}
2006-06-25 16:47:29 +04:00
static int ufs_statfs ( struct dentry * dentry , struct kstatfs * buf )
2005-04-17 02:20:36 +04:00
{
2006-06-23 13:02:58 +04:00
struct super_block * sb = dentry - > d_sb ;
2006-06-25 16:47:29 +04:00
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
unsigned flags = UFS_SB ( sb ) - > s_flags ;
struct ufs_super_block_first * usb1 ;
struct ufs_super_block_second * usb2 ;
struct ufs_super_block_third * usb3 ;
2009-04-03 03:59:44 +04:00
u64 id = huge_encode_dev ( sb - > s_bdev - > bd_dev ) ;
2005-04-17 02:20:36 +04:00
2011-01-24 12:14:12 +03:00
lock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:29 +04:00
usb1 = ubh_get_usb_first ( uspi ) ;
usb2 = ubh_get_usb_second ( uspi ) ;
usb3 = ubh_get_usb_third ( uspi ) ;
2005-04-17 02:20:36 +04:00
if ( ( flags & UFS_TYPE_MASK ) = = UFS_TYPE_UFS2 ) {
buf - > f_type = UFS2_MAGIC ;
2006-06-25 16:47:29 +04:00
buf - > f_blocks = fs64_to_cpu ( sb , usb3 - > fs_un1 . fs_u2 . fs_dsize ) ;
} else {
2005-04-17 02:20:36 +04:00
buf - > f_type = UFS_MAGIC ;
buf - > f_blocks = uspi - > s_dsize ;
}
2006-06-25 16:47:30 +04:00
buf - > f_bfree = ufs_blkstofrags ( uspi - > cs_total . cs_nbfree ) +
uspi - > cs_total . cs_nffree ;
buf - > f_ffree = uspi - > cs_total . cs_nifree ;
2005-04-17 02:20:36 +04:00
buf - > f_bsize = sb - > s_blocksize ;
buf - > f_bavail = ( buf - > f_bfree > ( ( ( long ) buf - > f_blocks / 100 ) * uspi - > s_minfree ) )
? ( buf - > f_bfree - ( ( ( long ) buf - > f_blocks / 100 ) * uspi - > s_minfree ) ) : 0 ;
buf - > f_files = uspi - > s_ncg * uspi - > s_ipg ;
buf - > f_namelen = UFS_MAXNAMLEN ;
2009-04-03 03:59:44 +04:00
buf - > f_fsid . val [ 0 ] = ( u32 ) id ;
buf - > f_fsid . val [ 1 ] = ( u32 ) ( id > > 32 ) ;
2005-04-17 02:20:36 +04:00
2011-01-24 12:14:12 +03:00
unlock_ufs ( sb ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-12-07 07:33:20 +03:00
static struct kmem_cache * ufs_inode_cachep ;
2005-04-17 02:20:36 +04:00
static struct inode * ufs_alloc_inode ( struct super_block * sb )
{
struct ufs_inode_info * ei ;
2011-01-24 12:14:12 +03:00
ei = ( struct ufs_inode_info * ) kmem_cache_alloc ( ufs_inode_cachep , GFP_NOFS ) ;
2005-04-17 02:20:36 +04:00
if ( ! ei )
return NULL ;
ei - > vfs_inode . i_version = 1 ;
return & ei - > vfs_inode ;
}
2011-01-07 09:49:49 +03:00
static void ufs_i_callback ( struct rcu_head * head )
2005-04-17 02:20:36 +04:00
{
2011-01-07 09:49:49 +03:00
struct inode * inode = container_of ( head , struct inode , i_rcu ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( ufs_inode_cachep , UFS_I ( inode ) ) ;
}
2011-01-07 09:49:49 +03:00
static void ufs_destroy_inode ( struct inode * inode )
{
call_rcu ( & inode - > i_rcu , ufs_i_callback ) ;
}
2008-07-26 06:45:34 +04:00
static void init_once ( void * foo )
2005-04-17 02:20:36 +04:00
{
struct ufs_inode_info * ei = ( struct ufs_inode_info * ) foo ;
2007-05-17 09:10:57 +04:00
inode_init_once ( & ei - > vfs_inode ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-20 05:11:58 +04:00
2005-04-17 02:20:36 +04:00
static int init_inodecache ( void )
{
ufs_inode_cachep = kmem_cache_create ( " ufs_inode_cache " ,
sizeof ( struct ufs_inode_info ) ,
2006-03-24 14:16:06 +03:00
0 , ( SLAB_RECLAIM_ACCOUNT |
SLAB_MEM_SPREAD ) ,
2007-07-20 05:11:58 +04:00
init_once ) ;
2005-04-17 02:20:36 +04:00
if ( ufs_inode_cachep = = NULL )
return - ENOMEM ;
return 0 ;
}
static void destroy_inodecache ( void )
{
2006-09-27 12:49:40 +04:00
kmem_cache_destroy ( ufs_inode_cachep ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:41 +03:00
static const struct super_operations ufs_super_ops = {
2005-04-17 02:20:36 +04:00
. alloc_inode = ufs_alloc_inode ,
. destroy_inode = ufs_destroy_inode ,
. write_inode = ufs_write_inode ,
2010-06-06 03:40:56 +04:00
. evict_inode = ufs_evict_inode ,
2005-04-17 02:20:36 +04:00
. put_super = ufs_put_super ,
2009-06-08 12:08:05 +04:00
. sync_fs = ufs_sync_fs ,
2005-04-17 02:20:36 +04:00
. statfs = ufs_statfs ,
. remount_fs = ufs_remount ,
2007-10-17 10:26:32 +04:00
. show_options = ufs_show_options ,
2005-04-17 02:20:36 +04:00
} ;
2010-07-25 00:46:55 +04:00
static struct dentry * ufs_mount ( struct file_system_type * fs_type ,
int flags , const char * dev_name , void * data )
2005-04-17 02:20:36 +04:00
{
2010-07-25 00:46:55 +04:00
return mount_bdev ( fs_type , flags , dev_name , data , ufs_fill_super ) ;
2005-04-17 02:20:36 +04:00
}
static struct file_system_type ufs_fs_type = {
. owner = THIS_MODULE ,
. name = " ufs " ,
2010-07-25 00:46:55 +04:00
. mount = ufs_mount ,
2005-04-17 02:20:36 +04:00
. kill_sb = kill_block_super ,
. fs_flags = FS_REQUIRES_DEV ,
} ;
static int __init init_ufs_fs ( void )
{
int err = init_inodecache ( ) ;
if ( err )
goto out1 ;
err = register_filesystem ( & ufs_fs_type ) ;
if ( err )
goto out ;
return 0 ;
out :
destroy_inodecache ( ) ;
out1 :
return err ;
}
static void __exit exit_ufs_fs ( void )
{
unregister_filesystem ( & ufs_fs_type ) ;
destroy_inodecache ( ) ;
}
module_init ( init_ufs_fs )
module_exit ( exit_ufs_fs )
MODULE_LICENSE ( " GPL " ) ;