* Stefan Reinauer <stepan@home.culture.mipt.ru>
*
* Module usage counts added on 96/04/29 by
- * Gertjan van Wingerde <gertjan@cs.vu.nl>
+ * Gertjan van Wingerde <gwingerde@gmail.com>
*
* Clean swab support on 19970406 by
* Francois-Rene Rideau <fare@tunes.org>
*/
+#include <linux/exportfs.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/ufs_fs.h>
+#include <linux/quotaops.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/stat.h>
#include <linux/mount.h>
#include <linux/seq_file.h>
+#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
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));
struct ufs_super_block_first * usb1;
va_list args;
+ lock_kernel();
uspi = UFS_SB(sb)->s_uspi;
usb1 = ubh_get_usb_first(uspi);
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"},
UFSD("ENTER\n");
+
+ lock_kernel();
+
ufs_put_cstotal(sb);
size = uspi->s_cssize;
blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
brelse (sbi->s_ucg[i]);
kfree (sbi->s_ucg);
kfree (base);
+
+ unlock_kernel();
+
UFSD("EXIT\n");
}
unsigned block_size, super_block_size;
unsigned flags;
unsigned super_block_offset;
+ unsigned maxsymlen;
+ int ret = -EINVAL;
uspi = NULL;
ubh = NULL;
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)
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)
*/
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:
* Read ufs_super_block into internal data structures
*/
sb->s_op = &ufs_super_ops;
+ sb->s_export_op = &ufs_export_ops;
sb->dq_op = NULL; /***/
sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic);
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);
/*
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)
UFSD("ENTER\n");
+ if (sb->s_dirt)
+ ufs_write_super(sb);
+
if (!(sb->s_flags & MS_RDONLY))
ufs_put_super_internal(sb);
struct ufs_super_block_third * usb3;
unsigned new_mount_opt, ufstype;
unsigned flags;
-
+
+ lock_kernel();
+ lock_super(sb);
uspi = UFS_SB(sb)->s_uspi;
flags = UFS_SB(sb)->s_flags;
usb1 = ubh_get_usb_first(uspi);
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;
}
#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_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;
#endif
}
UFS_SB(sb)->s_mount_opt = new_mount_opt;
+ unlock_super(sb);
+ unlock_kernel();
return 0;
}
{
struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb);
unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE;
- struct match_token *tp = tokens;
+ const struct match_token *tp = tokens;
while (tp->token != Opt_onerror_panic && tp->token != mval)
++tp;
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();
? (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();
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;
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,
.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,