]> git.karo-electronics.de Git - linux-beck.git/blobdiff - fs/fat/inode.c
fat (exportfs): rebuild inode if ilookup() fails
[linux-beck.git] / fs / fat / inode.c
index 93fbc8a7f0986a81ef7df9bb121573f6ff08a94d..971ba7d549da4960032d43ae7d7e507a607a9874 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/pagemap.h>
 #include <linux/mpage.h>
 #include <linux/buffer_head.h>
-#include <linux/exportfs.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
 #include <linux/parser.h>
@@ -444,12 +443,25 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
        return 0;
 }
 
+static inline void fat_lock_build_inode(struct msdos_sb_info *sbi)
+{
+       if (sbi->options.nfs == FAT_NFS_NOSTALE_RO)
+               mutex_lock(&sbi->nfs_build_inode_lock);
+}
+
+static inline void fat_unlock_build_inode(struct msdos_sb_info *sbi)
+{
+       if (sbi->options.nfs == FAT_NFS_NOSTALE_RO)
+               mutex_unlock(&sbi->nfs_build_inode_lock);
+}
+
 struct inode *fat_build_inode(struct super_block *sb,
                        struct msdos_dir_entry *de, loff_t i_pos)
 {
        struct inode *inode;
        int err;
 
+       fat_lock_build_inode(MSDOS_SB(sb));
        inode = fat_iget(sb, i_pos);
        if (inode)
                goto out;
@@ -469,6 +481,7 @@ struct inode *fat_build_inode(struct super_block *sb,
        fat_attach(inode, i_pos);
        insert_inode_hash(inode);
 out:
+       fat_unlock_build_inode(MSDOS_SB(sb));
        return inode;
 }
 
@@ -655,20 +668,6 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
-static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi,
-                                   struct inode *inode)
-{
-       loff_t i_pos;
-#if BITS_PER_LONG == 32
-       spin_lock(&sbi->inode_hash_lock);
-#endif
-       i_pos = MSDOS_I(inode)->i_pos;
-#if BITS_PER_LONG == 32
-       spin_unlock(&sbi->inode_hash_lock);
-#endif
-       return i_pos;
-}
-
 static int __fat_write_inode(struct inode *inode, int wait)
 {
        struct super_block *sb = inode->i_sb;
@@ -676,7 +675,8 @@ static int __fat_write_inode(struct inode *inode, int wait)
        struct buffer_head *bh;
        struct msdos_dir_entry *raw_entry;
        loff_t i_pos;
-       int err;
+       sector_t blocknr;
+       int err, offset;
 
        if (inode->i_ino == MSDOS_ROOT_INO)
                return 0;
@@ -686,7 +686,8 @@ retry:
        if (!i_pos)
                return 0;
 
-       bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
+       fat_get_blknr_offset(sbi, i_pos, &blocknr, &offset);
+       bh = sb_bread(sb, blocknr);
        if (!bh) {
                fat_msg(sb, KERN_ERR, "unable to read inode block "
                       "for updating (i_pos %lld)", i_pos);
@@ -699,8 +700,7 @@ retry:
                goto retry;
        }
 
-       raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
-           [i_pos & (sbi->dir_per_block - 1)];
+       raw_entry = &((struct msdos_dir_entry *) (bh->b_data))[offset];
        if (S_ISDIR(inode->i_mode))
                raw_entry->size = 0;
        else
@@ -761,12 +761,6 @@ static const struct super_operations fat_sops = {
        .show_options   = fat_show_options,
 };
 
-static const struct export_operations fat_export_ops = {
-       .fh_to_dentry   = fat_fh_to_dentry,
-       .fh_to_parent   = fat_fh_to_parent,
-       .get_parent     = fat_get_parent,
-};
-
 static int fat_show_options(struct seq_file *m, struct dentry *root)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb);
@@ -1190,8 +1184,10 @@ out:
                opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH);
        if (opts->unicode_xlate)
                opts->utf8 = 0;
-       if (opts->nfs == FAT_NFS_NOSTALE_RO)
+       if (opts->nfs == FAT_NFS_NOSTALE_RO) {
                sb->s_flags |= MS_RDONLY;
+               sb->s_export_op = &fat_export_ops_nostale;
+       }
 
        return 0;
 }
@@ -1202,7 +1198,7 @@ static int fat_read_root(struct inode *inode)
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        int error;
 
-       MSDOS_I(inode)->i_pos = 0;
+       MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO;
        inode->i_uid = sbi->options.fs_uid;
        inode->i_gid = sbi->options.fs_gid;
        inode->i_version++;
@@ -1265,6 +1261,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        sb->s_magic = MSDOS_SUPER_MAGIC;
        sb->s_op = &fat_sops;
        sb->s_export_op = &fat_export_ops;
+       mutex_init(&sbi->nfs_build_inode_lock);
        ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
                             DEFAULT_RATELIMIT_BURST);