ufs: NFS support
[safe/jmp/linux-2.6] / fs / ufs / super.c
index 6035929..143c20b 100644 (file)
@@ -66,6 +66,7 @@
  */
 
 
+#include <linux/exportfs.h>
 #include <linux/module.h>
 #include <linux/bitops.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
@@ -263,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);
        
@@ -594,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;
@@ -621,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");
 }
 
@@ -983,6 +1041,7 @@ magic_found:
         * 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);
 
@@ -1118,32 +1177,45 @@ failed_nomem:
        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)
@@ -1152,6 +1224,9 @@ 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);
        
@@ -1171,7 +1246,9 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
        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);
@@ -1184,17 +1261,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;
        }
        
@@ -1219,6 +1303,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 && 
@@ -1227,16 +1313,22 @@ 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;
 #endif
        }
        UFS_SB(sb)->s_mount_opt = new_mount_opt;
+       unlock_super(sb);
+       unlock_kernel();
        return 0;
 }
 
@@ -1352,6 +1444,7 @@ static const struct super_operations ufs_super_ops = {
        .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,