X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fufs%2Fsuper.c;h=2b08a8dd8ec0c06498b999a377e8d0ca4e5daa72;hb=287a80958cf63fc5c68d5bf6e89a3669dd66234a;hp=54828ebcf1bacda4d1c94dc4461cd99d8264234d;hpb=f99d49adf527fa6f7a9c42257fa76bca6b8df1e3;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 54828eb..2b08a8d 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -41,7 +41,7 @@ * Stefan Reinauer * * Module usage counts added on 96/04/29 by - * Gertjan van Wingerde + * Gertjan van Wingerde * * Clean swab support on 19970406 by * Francois-Rene Rideau @@ -61,10 +61,12 @@ * UFS2 (of FreeBSD 5.x) support added by * Niraj Kumar , Jan 2004 * + * UFS2 write support added by + * Evgeniy Dushistov , 2007 */ -#include +#include #include #include @@ -75,7 +77,7 @@ #include #include -#include +#include #include #include #include @@ -86,99 +88,153 @@ #include #include #include +#include +#include +#include +#include "ufs_fs.h" +#include "ufs.h" #include "swab.h" #include "util.h" -#undef UFS_SUPER_DEBUG -#undef UFS_SUPER_DEBUG_MORE +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); -#undef UFS_SUPER_DEBUG_MORE -#ifdef UFS_SUPER_DEBUG -#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif + 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; +} -#ifdef UFS_SUPER_DEBUG_MORE -/* - * Print contents of ufs_super_block, useful for debugging - */ -void ufs_print_super_stuff(struct super_block *sb, - struct ufs_super_block_first * usb1, - struct ufs_super_block_second * usb2, - struct ufs_super_block_third * usb3) +static struct dentry *ufs_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) { - printk("ufs_print_super_stuff\n"); - printk("size of usb: %u\n", sizeof(struct ufs_super_block)); - printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb3->fs_magic)); - 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(" contigsumsize: %d\n", fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize)); - printk(" postblformat: %u\n", fs32_to_cpu(sb, usb3->fs_postblformat)); - 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)); - printk("\n"); + 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) +{ + struct qstr dot_dot = { + .name = "..", + .len = 2, + }; + 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, +}; + +#ifdef CONFIG_UFS_DEBUG /* - * Print contents of ufs2 ufs_super_block, useful for debugging + * Print contents of ufs_super_block, useful for debugging */ -void ufs2_print_super_stuff( - struct super_block *sb, - struct ufs_super_block *usb) +static void ufs_print_super_stuff(struct super_block *sb, + struct ufs_super_block_first *usb1, + struct ufs_super_block_second *usb2, + struct ufs_super_block_third *usb3) { + u32 magic = fs32_to_cpu(sb, usb3->fs_magic); + printk("ufs_print_super_stuff\n"); - printk("size of usb: %u\n", sizeof(struct ufs_super_block)); - printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb->fs_magic)); - printk(" fs_size: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size)); - printk(" fs_dsize: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize)); - printk(" bsize: %u\n", fs32_to_cpu(usb, usb->fs_bsize)); - printk(" fsize: %u\n", fs32_to_cpu(usb, usb->fs_fsize)); - printk(" fs_volname: %s\n", usb->fs_u11.fs_u2.fs_volname); - printk(" fs_fsmnt: %s\n", usb->fs_u11.fs_u2.fs_fsmnt); - printk(" fs_sblockloc: %u\n",fs64_to_cpu(sb, - usb->fs_u11.fs_u2.fs_sblockloc)); - printk(" cs_ndir(No of dirs): %u\n",fs64_to_cpu(sb, - usb->fs_u11.fs_u2.fs_cstotal.cs_ndir)); - printk(" cs_nbfree(No of free blocks): %u\n",fs64_to_cpu(sb, - usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)); + printk(" magic: 0x%x\n", magic); + if (fs32_to_cpu(sb, usb3->fs_magic) == UFS2_MAGIC) { + 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)); + 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)); + printk(KERN_INFO" fs_maxsymlinklen: %u\n", + fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen)); + } 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)); + } printk("\n"); } /* * Print contents of ufs_cylinder_group, useful for debugging */ -void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group *cg) +static void ufs_print_cylinder_stuff(struct super_block *sb, + struct ufs_cylinder_group *cg) { printk("\nufs_print_cylinder_stuff\n"); - printk("size of ucg: %u\n", sizeof(struct ufs_cylinder_group)); + printk("size of ucg: %zu\n", sizeof(struct ufs_cylinder_group)); 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)); @@ -202,14 +258,20 @@ void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group 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)); - 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)); + 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)); printk("\n"); } -#endif /* UFS_SUPER_DEBUG_MORE */ +#else +# define ufs_print_super_stuff(sb, usb1, usb2, usb3) /**/ +# define ufs_print_cylinder_stuff(sb, cg) /**/ +#endif /* CONFIG_UFS_DEBUG */ -static struct super_operations ufs_super_ops; +static const struct super_operations ufs_super_ops; static char error_buf[1024]; @@ -221,16 +283,16 @@ void ufs_error (struct super_block * sb, const char * function, va_list args; uspi = UFS_SB(sb)->s_uspi; - usb1 = ubh_get_usb_first(USPI_UBH); + usb1 = ubh_get_usb_first(uspi); if (!(sb->s_flags & MS_RDONLY)) { usb1->fs_clean = UFS_FSBAD; - ubh_mark_buffer_dirty(USPI_UBH); + ubh_mark_buffer_dirty(USPI_UBH(uspi)); sb->s_dirt = 1; sb->s_flags |= MS_RDONLY; } va_start (args, fmt); - vsprintf (error_buf, fmt, args); + vsnprintf (error_buf, sizeof(error_buf), fmt, args); va_end (args); switch (UFS_SB(sb)->s_mount_opt & UFS_MOUNT_ONERROR) { case UFS_MOUNT_ONERROR_PANIC: @@ -252,16 +314,17 @@ void ufs_panic (struct super_block * sb, const char * function, struct ufs_super_block_first * usb1; va_list args; + lock_kernel(); uspi = UFS_SB(sb)->s_uspi; - usb1 = ubh_get_usb_first(USPI_UBH); + usb1 = ubh_get_usb_first(uspi); if (!(sb->s_flags & MS_RDONLY)) { usb1->fs_clean = UFS_FSBAD; - ubh_mark_buffer_dirty(USPI_UBH); + ubh_mark_buffer_dirty(USPI_UBH(uspi)); sb->s_dirt = 1; } va_start (args, fmt); - vsprintf (error_buf, fmt, args); + vsnprintf (error_buf, sizeof(error_buf), fmt, args); va_end (args); sb->s_flags |= MS_RDONLY; printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n", @@ -274,23 +337,35 @@ void ufs_warning (struct super_block * sb, const char * function, va_list args; va_start (args, fmt); - vsprintf (error_buf, fmt, args); + vsnprintf (error_buf, sizeof(error_buf), fmt, args); va_end (args); printk (KERN_WARNING "UFS-fs warning (device %s): %s: %s\n", sb->s_id, function, error_buf); } enum { - Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_44bsd, - Opt_type_ufs2, Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep, - Opt_type_openstep, Opt_onerror_panic, Opt_onerror_lock, - Opt_onerror_umount, Opt_onerror_repair, Opt_err + 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 }; -static match_table_t tokens = { +static const match_table_t tokens = { {Opt_type_old, "ufstype=old"}, {Opt_type_sunx86, "ufstype=sunx86"}, {Opt_type_sun, "ufstype=sun"}, + {Opt_type_sunos, "ufstype=sunos"}, {Opt_type_44bsd, "ufstype=44bsd"}, {Opt_type_ufs2, "ufstype=ufs2"}, {Opt_type_ufs2, "ufstype=5xbsd"}, @@ -298,6 +373,7 @@ static match_table_t tokens = { {Opt_type_nextstepcd, "ufstype=nextstep-cd"}, {Opt_type_nextstep, "ufstype=nextstep"}, {Opt_type_openstep, "ufstype=openstep"}, +/*end of possible ufs types */ {Opt_onerror_panic, "onerror=panic"}, {Opt_onerror_lock, "onerror=lock"}, {Opt_onerror_umount, "onerror=umount"}, @@ -309,7 +385,7 @@ static int ufs_parse_options (char * options, unsigned * mount_options) { char * p; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); if (!options) return 1; @@ -334,6 +410,10 @@ static int ufs_parse_options (char * options, unsigned * mount_options) ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_SUN); break; + case Opt_type_sunos: + ufs_clear_opt(*mount_options, UFSTYPE); + ufs_set_opt(*mount_options, UFSTYPE_SUNOS); + break; case Opt_type_44bsd: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_44BSD); @@ -386,26 +466,56 @@ static int ufs_parse_options (char * options, unsigned * mount_options) } /* + * Diffrent types of UFS hold fs_cstotal in different + * places, and use diffrent data structure for it. + * To make things simplier we just copy fs_cstotal to ufs_sb_private_info + */ +static void ufs_setup_cstotal(struct super_block *sb) +{ + struct ufs_sb_info *sbi = UFS_SB(sb); + struct ufs_sb_private_info *uspi = sbi->s_uspi; + struct ufs_super_block_first *usb1; + struct ufs_super_block_second *usb2; + struct ufs_super_block_third *usb3; + 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; - struct ufs_super_block *usb; +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; struct ufs_buffer_head * ubh; unsigned char * base, * space; unsigned size, blks, i; - unsigned flags = 0; - - UFSD(("ENTER\n")) - - uspi = sbi->s_uspi; + struct ufs_super_block_third *usb3; - usb = (struct ufs_super_block *) - ((struct ufs_buffer_head *)uspi)->bh[0]->b_data; + UFSD("ENTER\n"); - flags = UFS_SB(sb)->s_flags; - + usb3 = ubh_get_usb_third(uspi); /* * Read cs structures from (usually) first data block * on the device. @@ -415,26 +525,19 @@ static int ufs_read_cylinder_structures (struct super_block *sb) { base = space = kmalloc(size, GFP_KERNEL); if (!base) goto failed; + sbi->s_csp = (struct ufs_csum *)space; 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; - if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { - ubh = ubh_bread(sb, - fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size); - if (!ubh) - goto failed; - ubh_ubhcpymem (space, ubh, size); - sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space; - } - else { - ubh = ubh_bread(sb, uspi->s_csaddr + i, size); - if (!ubh) - goto failed; - ubh_ubhcpymem(space, ubh, size); - sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space; - } + ubh = ubh_bread(sb, uspi->s_csaddr + i, size); + + if (!ubh) + goto failed; + + ubh_ubhcpymem (space, ubh, size); + space += size; ubh_brelse (ubh); ubh = NULL; @@ -453,14 +556,13 @@ static int ufs_read_cylinder_structures (struct super_block *sb) { sbi->s_cgno[i] = UFS_CGNO_EMPTY; } for (i = 0; i < uspi->s_ncg; i++) { - UFSD(("read cg %u\n", i)) + UFSD("read cg %u\n", i); 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; -#ifdef UFS_SUPER_DEBUG_MORE + ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data); -#endif } for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL))) @@ -468,7 +570,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb) { sbi->s_cgno[i] = UFS_CGNO_EMPTY; } sbi->s_cg_loaded = 0; - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return 1; failed: @@ -481,33 +583,83 @@ failed: for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) kfree (sbi->s_ucpi[i]); } - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return 0; } /* - * Put on-disk structures associated with cylinder groups and - * write them back to disk + * Sync our internal copy of fs_cstotal with disk */ -static void ufs_put_cylinder_structures (struct super_block *sb) { - struct ufs_sb_info * sbi = UFS_SB(sb); - struct ufs_sb_private_info * uspi; +static void ufs_put_cstotal(struct super_block *sb) +{ + 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)); + ufs_print_super_stuff(sb, usb1, usb2, usb3); + 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; struct ufs_buffer_head * ubh; unsigned char * base, * space; unsigned blks, size, i; + - UFSD(("ENTER\n")) - - uspi = sbi->s_uspi; + UFSD("ENTER\n"); + lock_kernel(); + + ufs_put_cstotal(sb); size = uspi->s_cssize; blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; - base = space = (char*) sbi->s_csp[0]; + base = space = (char*) sbi->s_csp; 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; + ubh = ubh_bread(sb, uspi->s_csaddr + i, size); + ubh_memcpyubh (ubh, space, size); space += size; ubh_mark_buffer_uptodate (ubh, 1); @@ -524,7 +676,10 @@ static void ufs_put_cylinder_structures (struct super_block *sb) { brelse (sbi->s_ucg[i]); kfree (sbi->s_ucg); kfree (base); - UFSD(("EXIT\n")) + + unlock_kernel(); + + UFSD("EXIT\n"); } static int ufs_fill_super(struct super_block *sb, void *data, int silent) @@ -534,25 +689,26 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) struct ufs_super_block_first * usb1; struct ufs_super_block_second * usb2; struct ufs_super_block_third * usb3; - struct ufs_super_block *usb; struct ufs_buffer_head * ubh; struct inode *inode; unsigned block_size, super_block_size; unsigned flags; + unsigned super_block_offset; + unsigned maxsymlen; + int ret = -EINVAL; uspi = NULL; ubh = NULL; flags = 0; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); - sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL); + sbi = kzalloc(sizeof(struct ufs_sb_info), GFP_KERNEL); if (!sbi) goto failed_nomem; sb->s_fs_info = sbi; - memset(sbi, 0, sizeof(struct ufs_sb_info)); - UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY))) + UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY)); #ifndef CONFIG_UFS_FS_WRITE if (!(sb->s_flags & MS_RDONLY)) { @@ -575,24 +731,25 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) if (!silent) printk("You didn't specify the type of your ufs filesystem\n\n" "mount -t ufs -o ufstype=" - "sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n" + "sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|nextstep-cd|openstep ...\n\n" ">>>WARNING<<< Wrong ufstype may corrupt your filesystem, " "default is ufstype=old\n"); ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD); } - sbi->s_uspi = uspi = - kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL); + uspi = kzalloc(sizeof(struct ufs_sb_private_info), GFP_KERNEL); + sbi->s_uspi = uspi; if (!uspi) goto failed; + uspi->s_dirblksize = UFS_SECTOR_SIZE; + super_block_offset=UFS_SBLOCK; /* 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: - UFSD(("ufstype=44bsd\n")) + UFSD("ufstype=44bsd\n"); uspi->s_fsize = block_size = 512; uspi->s_fmask = ~(512 - 1); uspi->s_fshift = 9; @@ -601,43 +758,52 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; break; case UFS_MOUNT_UFSTYPE_UFS2: - UFSD(("ufstype=ufs2\n")) + UFSD("ufstype=ufs2\n"); + super_block_offset=SBLOCK_UFS2; 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; - if (!(sb->s_flags & MS_RDONLY)) { - printk(KERN_INFO "ufstype=ufs2 is supported read-only\n"); - sb->s_flags |= MS_RDONLY; - } break; case UFS_MOUNT_UFSTYPE_SUN: - UFSD(("ufstype=sun\n")) + UFSD("ufstype=sun\n"); 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; - uspi->s_maxsymlinklen = 56; + uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN; break; + 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; + case UFS_MOUNT_UFSTYPE_SUNx86: - UFSD(("ufstype=sunx86\n")) + UFSD("ufstype=sunx86\n"); 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; - uspi->s_maxsymlinklen = 56; + uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN; break; case UFS_MOUNT_UFSTYPE_OLD: - UFSD(("ufstype=old\n")) + UFSD("ufstype=old\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; @@ -652,12 +818,13 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP: - UFSD(("ufstype=nextstep\n")) + UFSD("ufstype=nextstep\n"); 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; + uspi->s_dirblksize = 1024; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) @@ -667,12 +834,13 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD: - UFSD(("ufstype=nextstep-cd\n")) + UFSD("ufstype=nextstep-cd\n"); 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; + uspi->s_dirblksize = 1024; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) @@ -682,12 +850,13 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_OPENSTEP: - UFSD(("ufstype=openstep\n")) + UFSD("ufstype=openstep\n"); 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; + uspi->s_dirblksize = 1024; flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) @@ -697,7 +866,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_HP: - UFSD(("ufstype=hp\n")) + UFSD("ufstype=hp\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; @@ -725,21 +894,23 @@ again: /* * read ufs super block from device */ - if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { - ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + SBLOCK_UFS2/block_size, super_block_size); - } - else { - ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size); - } + + ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + super_block_offset/block_size, super_block_size); + if (!ubh) goto failed; - - usb1 = ubh_get_usb_first(USPI_UBH); - usb2 = ubh_get_usb_second(USPI_UBH); - usb3 = ubh_get_usb_third(USPI_UBH); - usb = (struct ufs_super_block *) - ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ; + usb1 = ubh_get_usb_first(uspi); + usb2 = ubh_get_usb_second(uspi); + usb3 = ubh_get_usb_third(uspi); + + /* 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; + } /* * Check ufs magic number @@ -786,7 +957,7 @@ magic_found: uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask); uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift); - if (uspi->s_fsize & (uspi->s_fsize - 1)) { + if (!is_power_of_2(uspi->s_fsize)) { printk(KERN_ERR "ufs_read_super: fragment size %u is not a power of 2\n", uspi->s_fsize); goto failed; @@ -801,7 +972,7 @@ magic_found: uspi->s_fsize); goto failed; } - if (uspi->s_bsize & (uspi->s_bsize - 1)) { + if (!is_power_of_2(uspi->s_bsize)) { printk(KERN_ERR "ufs_read_super: block size %u is not a power of 2\n", uspi->s_bsize); goto failed; @@ -821,16 +992,12 @@ magic_found: ubh = NULL; block_size = uspi->s_fsize; super_block_size = uspi->s_sbsize; - UFSD(("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size)) + UFSD("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size); goto again; } -#ifdef UFS_SUPER_DEBUG_MORE - if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) - ufs2_print_super_stuff(sb,usb); - else - ufs_print_super_stuff(sb, usb1, usb2, usb3); -#endif + sbi->s_flags = flags;/*after that line some functions use s_flags*/ + ufs_print_super_stuff(sb, usb1, usb2, usb3); /* * Check, if file system was correctly unmounted. @@ -838,18 +1005,22 @@ magic_found: */ 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_SUNx86) && + (((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))))) { switch(usb1->fs_clean) { case UFS_FSCLEAN: - UFSD(("fs is clean\n")) + UFSD("fs is clean\n"); break; case UFS_FSSTABLE: - UFSD(("fs is stable\n")) + UFSD("fs is stable\n"); + break; + case UFS_FSLOG: + UFSD("fs is logging fs\n"); break; case UFS_FSOSF1: - UFSD(("fs is DEC OSF/1\n")) + UFSD("fs is DEC OSF/1\n"); break; case UFS_FSACTIVE: printk("ufs_read_super: fs is active\n"); @@ -864,8 +1035,7 @@ magic_found: sb->s_flags |= MS_RDONLY; break; } - } - else { + } else { printk("ufs_read_super: fs needs fsck\n"); sb->s_flags |= MS_RDONLY; } @@ -874,7 +1044,12 @@ magic_found: * Read ufs_super_block into internal data structures */ sb->s_op = &ufs_super_ops; - sb->dq_op = NULL; /***/ + sb->s_export_op = &ufs_export_ops; +#ifdef CONFIG_QUOTA + sb->s_qcop = &dquot_quotactl_ops; + sb->dq_op = NULL; /* &dquot_operations */ +#endif + sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic); uspi->s_sblkno = fs32_to_cpu(sb, usb1->fs_sblkno); @@ -885,10 +1060,9 @@ magic_found: uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask); if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { - uspi->s_u2_size = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size); - uspi->s_u2_dsize = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize); - } - else { + 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 { uspi->s_size = fs32_to_cpu(sb, usb1->fs_size); uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize); } @@ -902,8 +1076,8 @@ magic_found: 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); - UFSD(("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift, - uspi->s_fshift)); + UFSD("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift, + uspi->s_fshift); uspi->s_fpbshift = fs32_to_cpu(sb, usb1->fs_fragshift); uspi->s_fsbtodb = fs32_to_cpu(sb, usb1->fs_fsbtodb); /* s_sbsize already set */ @@ -915,7 +1089,12 @@ magic_found: 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); - uspi->s_csaddr = fs32_to_cpu(sb, usb1->fs_csaddr); + + 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); + 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); @@ -923,11 +1102,10 @@ magic_found: 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); - uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_cpc); - uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize); + 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); uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3); uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3); - uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat); 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); @@ -936,12 +1114,11 @@ magic_found: * Compute another frequently used values */ uspi->s_fpbmask = uspi->s_fpb - 1; - if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) uspi->s_apbshift = uspi->s_bshift - 3; - } - else { + else uspi->s_apbshift = uspi->s_bshift - 2; - } + uspi->s_2apbshift = uspi->s_apbshift * 2; uspi->s_3apbshift = uspi->s_apbshift * 3; uspi->s_apb = 1 << uspi->s_apbshift; @@ -954,21 +1131,33 @@ magic_found: uspi->s_bpf = uspi->s_fsize << 3; uspi->s_bpfshift = uspi->s_fshift + 3; uspi->s_bpfmask = uspi->s_bpf - 1; - if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == - UFS_MOUNT_UFSTYPE_44BSD) + if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_44BSD || + (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_UFS2) uspi->s_maxsymlinklen = - fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_maxsymlinklen); - - sbi->s_flags = flags; + fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen); + + 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; + } - inode = iget(sb, UFS_ROOTINO); - if (!inode || is_bad_inode(inode)) + inode = ufs_iget(sb, UFS_ROOTINO); + if (IS_ERR(inode)) { + ret = PTR_ERR(inode); goto failed; + } sb->s_root = d_alloc_root(inode); - if (!sb->s_root) + if (!sb->s_root) { + ret = -ENOMEM; goto dalloc_failed; + } - + ufs_setup_cstotal(sb); /* * Read cylinder group structures */ @@ -976,7 +1165,7 @@ magic_found: if (!ufs_read_cylinder_structures(sb)) goto failed; - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return 0; dalloc_failed: @@ -987,54 +1176,74 @@ failed: kfree (uspi); kfree(sbi); sb->s_fs_info = NULL; - UFSD(("EXIT (FAILED)\n")) - return -EINVAL; + UFSD("EXIT (FAILED)\n"); + return ret; failed_nomem: - UFSD(("EXIT (NOMEM)\n")) + UFSD("EXIT (NOMEM)\n"); return -ENOMEM; } -static void ufs_write_super (struct super_block *sb) { +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_super(sb); lock_kernel(); - UFSD(("ENTER\n")) + UFSD("ENTER\n"); + flags = UFS_SB(sb)->s_flags; uspi = UFS_SB(sb)->s_uspi; - usb1 = ubh_get_usb_first(USPI_UBH); - usb3 = ubh_get_usb_third(USPI_UBH); - - if (!(sb->s_flags & MS_RDONLY)) { - usb1->fs_time = cpu_to_fs32(sb, get_seconds()); - if ((flags & UFS_ST_MASK) == UFS_ST_SUN - || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) - ufs_set_fs_state(sb, usb1, usb3, - UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); - ubh_mark_buffer_dirty (USPI_UBH); - } + 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); sb->s_dirt = 0; - UFSD(("EXIT\n")) + + UFSD("EXIT\n"); unlock_kernel(); + unlock_super(sb); + + return 0; } -static void ufs_put_super (struct super_block *sb) +static void ufs_write_super(struct super_block *sb) +{ + if (!(sb->s_flags & MS_RDONLY)) + ufs_sync_fs(sb, 1); + else + sb->s_dirt = 0; +} + +static void ufs_put_super(struct super_block *sb) { struct ufs_sb_info * sbi = UFS_SB(sb); - UFSD(("ENTER\n")) + UFSD("ENTER\n"); + + dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); + + if (sb->s_dirt) + ufs_write_super(sb); if (!(sb->s_flags & MS_RDONLY)) - ufs_put_cylinder_structures (sb); + ufs_put_super_internal(sb); ubh_brelse_uspi (sbi->s_uspi); kfree (sbi->s_uspi); kfree (sbi); sb->s_fs_info = NULL; + UFSD("EXIT\n"); return; } @@ -1045,12 +1254,16 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) struct ufs_super_block_first * usb1; struct ufs_super_block_third * usb3; unsigned new_mount_opt, ufstype; + int enable_quota = 0; unsigned flags; - + int err; + + lock_kernel(); + lock_super(sb); uspi = UFS_SB(sb)->s_uspi; flags = UFS_SB(sb)->s_flags; - usb1 = ubh_get_usb_first(USPI_UBH); - usb3 = ubh_get_usb_third(USPI_UBH); + usb1 = ubh_get_usb_first(uspi); + usb3 = ubh_get_usb_third(uspi); /* * Allow the "check" option to be passed as a remount option. @@ -1059,18 +1272,24 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) ufstype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE; new_mount_opt = 0; ufs_set_opt (new_mount_opt, ONERROR_LOCK); - if (!ufs_parse_options (data, &new_mount_opt)) + if (!ufs_parse_options (data, &new_mount_opt)) { + unlock_super(sb); + unlock_kernel(); return -EINVAL; + } if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) { new_mount_opt |= ufstype; - } - else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { + } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { printk("ufstype can't be changed during remount\n"); + unlock_super(sb); + unlock_kernel(); return -EINVAL; } if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { UFS_SB(sb)->s_mount_opt = new_mount_opt; + unlock_super(sb); + unlock_kernel(); return 0; } @@ -1078,89 +1297,127 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) * fs was mouted as rw, remounting ro */ if (*mount_flags & MS_RDONLY) { - ufs_put_cylinder_structures(sb); + err = dquot_suspend(sb, -1); + if (err < 0) { + unlock_super(sb); + unlock_kernel(); + return err; + } + + ufs_put_super_internal(sb); 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)); - ubh_mark_buffer_dirty (USPI_UBH); + ubh_mark_buffer_dirty (USPI_UBH(uspi)); sb->s_dirt = 0; sb->s_flags |= MS_RDONLY; - } + } else { /* * fs was mounted as ro, remounting rw */ - else { #ifndef CONFIG_UFS_FS_WRITE printk("ufs was compiled with read-only support, " "can't be mounted as read-write\n"); + unlock_super(sb); + unlock_kernel(); return -EINVAL; #else if (ufstype != UFS_MOUNT_UFSTYPE_SUN && + ufstype != UFS_MOUNT_UFSTYPE_SUNOS && ufstype != UFS_MOUNT_UFSTYPE_44BSD && - ufstype != UFS_MOUNT_UFSTYPE_SUNx86) { + ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && + ufstype != UFS_MOUNT_UFSTYPE_UFS2) { printk("this ufstype is read-only supported\n"); + unlock_super(sb); + unlock_kernel(); return -EINVAL; } - if (!ufs_read_cylinder_structures (sb)) { + if (!ufs_read_cylinder_structures(sb)) { printk("failed during remounting\n"); + unlock_super(sb); + unlock_kernel(); return -EPERM; } sb->s_flags &= ~MS_RDONLY; + enable_quota = 1; #endif } UFS_SB(sb)->s_mount_opt = new_mount_opt; + unlock_super(sb); + unlock_kernel(); + if (enable_quota) + dquot_resume(sb, -1); return 0; } -static int ufs_statfs (struct super_block *sb, struct kstatfs *buf) +static int ufs_show_options(struct seq_file *seq, struct vfsmount *vfs) { - struct ufs_sb_private_info * uspi; - struct ufs_super_block_first * usb1; - struct ufs_super_block * usb; - unsigned flags = 0; + struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb); + unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE; + const struct match_token *tp = tokens; + + 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; +} + +static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct super_block *sb = dentry->d_sb; + 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; + u64 id = huge_encode_dev(sb->s_bdev->bd_dev); lock_kernel(); - uspi = UFS_SB(sb)->s_uspi; - usb1 = ubh_get_usb_first (USPI_UBH); - usb = (struct ufs_super_block *) - ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ; + usb1 = ubh_get_usb_first(uspi); + usb2 = ubh_get_usb_second(uspi); + usb3 = ubh_get_usb_third(uspi); - flags = UFS_SB(sb)->s_flags; if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { buf->f_type = UFS2_MAGIC; - buf->f_blocks = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize); - buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) + - fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree); - buf->f_ffree = fs64_to_cpu(sb, - usb->fs_u11.fs_u2.fs_cstotal.cs_nifree); - } - else { + buf->f_blocks = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize); + } else { buf->f_type = UFS_MAGIC; buf->f_blocks = uspi->s_dsize; - buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) + - fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree); - buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree); } + buf->f_bfree = ufs_blkstofrags(uspi->cs_total.cs_nbfree) + + uspi->cs_total.cs_nffree; + buf->f_ffree = uspi->cs_total.cs_nifree; 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; + buf->f_fsid.val[0] = (u32)id; + buf->f_fsid.val[1] = (u32)(id >> 32); unlock_kernel(); return 0; } -static kmem_cache_t * ufs_inode_cachep; +static struct kmem_cache * ufs_inode_cachep; static struct inode *ufs_alloc_inode(struct super_block *sb) { struct ufs_inode_info *ei; - ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, SLAB_KERNEL); + ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, GFP_KERNEL); if (!ei) return NULL; ei->vfs_inode.i_version = 1; @@ -1172,21 +1429,20 @@ static void ufs_destroy_inode(struct inode *inode) kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); } -static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void init_once(void *foo) { struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; - if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) - inode_init_once(&ei->vfs_inode); + inode_init_once(&ei->vfs_inode); } - + static int init_inodecache(void) { ufs_inode_cachep = kmem_cache_create("ufs_inode_cache", sizeof(struct ufs_inode_info), - 0, SLAB_RECLAIM_ACCOUNT, - init_once, NULL); + 0, (SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), + init_once); if (ufs_inode_cachep == NULL) return -ENOMEM; return 0; @@ -1194,8 +1450,12 @@ static int init_inodecache(void) static void destroy_inodecache(void) { - if (kmem_cache_destroy(ufs_inode_cachep)) - printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n"); + kmem_cache_destroy(ufs_inode_cachep); +} + +static void ufs_clear_inode(struct inode *inode) +{ + dquot_drop(inode); } #ifdef CONFIG_QUOTA @@ -1203,16 +1463,18 @@ static ssize_t ufs_quota_read(struct super_block *, int, char *,size_t, loff_t); static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t, loff_t); #endif -static struct super_operations ufs_super_ops = { +static const struct super_operations ufs_super_ops = { .alloc_inode = ufs_alloc_inode, .destroy_inode = ufs_destroy_inode, - .read_inode = ufs_read_inode, .write_inode = ufs_write_inode, .delete_inode = ufs_delete_inode, + .clear_inode = ufs_clear_inode, .put_super = ufs_put_super, .write_super = ufs_write_super, + .sync_fs = ufs_sync_fs, .statfs = ufs_statfs, .remount_fs = ufs_remount, + .show_options = ufs_show_options, #ifdef CONFIG_QUOTA .quota_read = ufs_quota_read, .quota_write = ufs_quota_write, @@ -1275,7 +1537,7 @@ static ssize_t ufs_quota_write(struct super_block *sb, int type, size_t towrite = len; struct buffer_head *bh; - down(&inode->i_sem); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; @@ -1296,23 +1558,25 @@ static ssize_t ufs_quota_write(struct super_block *sb, int type, blk++; } out: - if (len == towrite) + if (len == towrite) { + mutex_unlock(&inode->i_mutex); return err; + } if (inode->i_size < off+len-towrite) i_size_write(inode, off+len-towrite); inode->i_version++; inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - up(&inode->i_sem); + mutex_unlock(&inode->i_mutex); return len - towrite; } #endif -static struct super_block *ufs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int ufs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super, mnt); } static struct file_system_type ufs_fs_type = {