X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fufs%2Fsuper.c;h=2b08a8dd8ec0c06498b999a377e8d0ca4e5daa72;hb=287a80958cf63fc5c68d5bf6e89a3669dd66234a;hp=87f6b51a895d500b8606da7aadc7d9ec8e5a18ac;hpb=252e211e90ce56bf005cb533ad5a297c18c19407;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 87f6b51..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 @@ -66,6 +66,7 @@ */ +#include #include #include @@ -76,7 +77,7 @@ #include #include -#include +#include #include #include #include @@ -88,10 +89,64 @@ #include #include #include +#include +#include +#include "ufs_fs.h" +#include "ufs.h" #include "swab.h" #include "util.h" +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) +{ + 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 ufs_super_block, useful for debugging @@ -128,6 +183,8 @@ static void ufs_print_super_stuff(struct super_block *sb, 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)); @@ -257,6 +314,7 @@ 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); @@ -286,13 +344,24 @@ void ufs_warning (struct super_block * sb, const char * function, } enum { - Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_sunos, 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"}, @@ -304,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"}, @@ -576,6 +646,9 @@ static void ufs_put_super_internal(struct super_block *sb) UFSD("ENTER\n"); + + lock_kernel(); + ufs_put_cstotal(sb); size = uspi->s_cssize; blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; @@ -603,6 +676,9 @@ static void ufs_put_super_internal(struct super_block *sb) brelse (sbi->s_ucg[i]); kfree (sbi->s_ucg); kfree (base); + + unlock_kernel(); + UFSD("EXIT\n"); } @@ -618,6 +694,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) unsigned block_size, super_block_size; unsigned flags; unsigned super_block_offset; + unsigned maxsymlen; + int ret = -EINVAL; uspi = NULL; ubh = NULL; @@ -740,13 +818,13 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP: - /*TODO: check may be we need set special dir block size?*/ 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) @@ -756,13 +834,13 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD: - /*TODO: check may be we need set special dir block size?*/ 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) @@ -927,9 +1005,9 @@ 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_SUN || (flags & UFS_ST_MASK) == UFS_ST_SUNOS || - (flags & UFS_ST_MASK) == UFS_ST_SUNx86) && + (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: @@ -938,6 +1016,9 @@ magic_found: case UFS_FSSTABLE: 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"); break; @@ -963,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); @@ -1045,17 +1131,31 @@ 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_un2.fs_44.fs_maxsymlinklen); - inode = iget(sb, UFS_ROOTINO); - if (!inode || is_bad_inode(inode)) + 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 = 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); /* @@ -1077,39 +1177,52 @@ failed: kfree(sbi); sb->s_fs_info = NULL; UFSD("EXIT (FAILED)\n"); - return -EINVAL; + return ret; failed_nomem: 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"); + flags = UFS_SB(sb)->s_flags; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); usb3 = ubh_get_usb_third(uspi); - 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_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); - } + 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"); unlock_kernel(); + unlock_super(sb); + + return 0; +} + +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) @@ -1118,6 +1231,11 @@ static void ufs_put_super(struct super_block *sb) 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_super_internal(sb); @@ -1136,8 +1254,12 @@ 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); @@ -1150,17 +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) { 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; } @@ -1168,6 +1297,13 @@ 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) { + 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 @@ -1185,6 +1321,8 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) #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 && @@ -1193,16 +1331,45 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) 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)) { 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_show_options(struct seq_file *seq, struct vfsmount *vfs) +{ + 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; } @@ -1214,6 +1381,7 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) 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(); @@ -1236,6 +1404,8 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) ? (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(); @@ -1259,7 +1429,7 @@ static void ufs_destroy_inode(struct inode *inode) kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); } -static void init_once(struct kmem_cache * cachep, void *foo) +static void init_once(void *foo) { struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; @@ -1283,6 +1453,11 @@ static void destroy_inodecache(void) kmem_cache_destroy(ufs_inode_cachep); } +static void ufs_clear_inode(struct inode *inode) +{ + dquot_drop(inode); +} + #ifdef CONFIG_QUOTA 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); @@ -1291,13 +1466,15 @@ static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t, 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,