patch-2.1.82 linux/fs/nfs/inode.c
Next file: linux/fs/nfs/nfs2xdr.c
Previous file: linux/fs/nfs/dir.c
Back to the patch index
Back to the overall index
- Lines: 264
- Date:
Sat Jan 24 10:53:00 1998
- Orig file:
v2.1.81/linux/fs/nfs/inode.c
- Orig date:
Fri Jan 16 11:24:09 1998
diff -u --recursive --new-file v2.1.81/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
@@ -32,9 +32,12 @@
#include <asm/system.h>
#include <asm/uaccess.h>
+#define CONFIG_NFS_SNAPSHOT 1
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1
+static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
+
static void nfs_read_inode(struct inode *);
static void nfs_put_inode(struct inode *);
static void nfs_delete_inode(struct inode *);
@@ -190,6 +193,7 @@
int tcp;
struct sockaddr_in srvaddr;
struct rpc_timeout timeparms;
+ struct nfs_fattr fattr;
MOD_INC_USE_COUNT;
if (!data)
@@ -274,7 +278,10 @@
goto out_no_fh;
*root_fh = data->root;
- root_inode = nfs_fhget(sb, &data->root, NULL);
+ if (nfs_proc_getattr(server, root_fh, &fattr) != 0)
+ goto out_no_fattr;
+
+ root_inode = __nfs_fhget(sb, &fattr);
if (!root_inode)
goto out_no_root;
sb->s_root = d_alloc_root(root_inode, NULL);
@@ -295,6 +302,11 @@
out_no_root:
printk("nfs_read_super: get root inode failed\n");
iput(root_inode);
+ goto out_free_fh;
+
+out_no_fattr:
+ printk("nfs_read_super: get root fattr failed\n");
+out_free_fh:
kfree(root_fh);
out_no_fh:
rpciod_down();
@@ -384,42 +396,110 @@
}
/*
+ * Fill in inode information from the fattr.
+ */
+static void
+nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
+{
+ /*
+ * Check whether the mode has been set, as we only want to
+ * do this once. (We don't allow inodes to change types.)
+ */
+ if (inode->i_mode == 0) {
+ inode->i_mode = fattr->mode;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &nfs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &nfs_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &nfs_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode)) {
+ inode->i_op = &chrdev_inode_operations;
+ inode->i_rdev = to_kdev_t(fattr->rdev);
+ } else if (S_ISBLK(inode->i_mode)) {
+ inode->i_op = &blkdev_inode_operations;
+ inode->i_rdev = to_kdev_t(fattr->rdev);
+ } else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+ else
+ inode->i_op = NULL;
+ /*
+ * Preset the size and mtime, as there's no need
+ * to invalidate the caches.
+ */
+ inode->i_size = fattr->size;
+ inode->i_mtime = fattr->mtime.seconds;
+ NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+ }
+ nfs_refresh_inode(inode, fattr);
+}
+
+/*
* This is our own version of iget that looks up inodes by file handle
* instead of inode number. We use this technique instead of using
* the vfs read_inode function because there is no way to pass the
* file handle or current attributes into the read_inode function.
*
+ * We provide a special check for NetApp .snapshot directories to avoid
+ * inode aliasing problems. All snapshot inodes are anonymous (unhashed).
+ */
+struct inode *
+nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ struct super_block *sb = dentry->d_sb;
+
+ dprintk("NFS: nfs_fhget(%s/%s fileid=%d)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ fattr->fileid);
+
+ /* Install the filehandle in the dentry */
+ *((struct nfs_fh *) dentry->d_fsdata) = *fhandle;
+
+#ifdef CONFIG_NFS_SNAPSHOT
+ /*
+ * Check for NetApp snapshot dentries, and get an
+ * unhashed inode to avoid aliasing problems.
+ */
+ if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
+ (IS_ROOT(dentry->d_parent) && dentry->d_name.len == 9 &&
+ memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
+ struct inode *inode = get_empty_inode();
+ if (!inode)
+ goto out;
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_ino = fattr->fileid;
+ nfs_read_inode(inode);
+ nfs_fill_inode(inode, fattr);
+ inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
+ dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino);
+ out:
+ return inode;
+ }
+#endif
+ return __nfs_fhget(sb, fattr);
+}
+
+/*
+ * Look up the inode by super block and fattr->fileid.
+ *
* Note carefully the special handling of busy inodes (i_count > 1).
- * With the Linux 2.1.xx dcache all inodes except hard links must
+ * With the kernel 2.1.xx dcache all inodes except hard links must
* have i_count == 1 after iget(). Otherwise, it indicates that the
* server has reused a fileid (i_ino) and we have a stale inode.
*/
-struct inode *
-nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+static struct inode *
+__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
{
- int error, max_count;
- struct inode *inode = NULL;
- struct nfs_fattr newfattr;
-
- if (!sb)
- goto out_bad_args;
- if (!fattr) {
- fattr = &newfattr;
- error = nfs_proc_getattr(&sb->u.nfs_sb.s_server, fhandle,fattr);
- if (error)
- goto out_bad_attr;
- }
+ struct inode *inode;
+ int max_count;
retry:
inode = iget(sb, fattr->fileid);
if (!inode)
goto out_no_inode;
-#ifdef NFS_PARANOIA
-if (inode->i_dev != sb->s_dev)
-printk("nfs_fhget: impossible\n");
-#endif
-
+ /* N.B. This should be impossible ... */
if (inode->i_ino != fattr->fileid)
goto out_bad_id;
@@ -434,19 +514,20 @@
*/
max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
if (inode->i_count > max_count) {
-printk("nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
+printk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
inode->i_ino, inode->i_count, inode->i_nlink);
nfs_free_dentries(inode);
if (inode->i_count > max_count) {
-printk("nfs_fhget: inode %ld still busy, i_count=%d\n",
+printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
inode->i_ino, inode->i_count);
if (!list_empty(&inode->i_dentry)) {
struct dentry *dentry;
dentry = list_entry(inode->i_dentry.next,
struct dentry, d_alias);
-printk("nfs_fhget: killing %s/%s filehandle\n",
+printk("__nfs_fhget: killing %s/%s filehandle\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- memset(dentry->d_fsdata, 0, sizeof(*fhandle));
+ memset(dentry->d_fsdata, 0,
+ sizeof(struct nfs_fh));
} else
printk("NFS: inode %ld busy, no aliases?\n",
inode->i_ino);
@@ -456,56 +537,18 @@
iput(inode);
goto retry;
}
-
- /*
- * Check whether the mode has been set, as we only want to
- * do this once. (We don't allow inodes to change types.)
- */
- if (inode->i_mode == 0) {
- inode->i_mode = fattr->mode;
- if (S_ISREG(inode->i_mode))
- inode->i_op = &nfs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
- inode->i_op = &nfs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &nfs_symlink_inode_operations;
- else if (S_ISCHR(inode->i_mode)) {
- inode->i_op = &chrdev_inode_operations;
- inode->i_rdev = to_kdev_t(fattr->rdev);
- } else if (S_ISBLK(inode->i_mode)) {
- inode->i_op = &blkdev_inode_operations;
- inode->i_rdev = to_kdev_t(fattr->rdev);
- } else if (S_ISFIFO(inode->i_mode))
- init_fifo(inode);
- else
- inode->i_op = NULL;
- /*
- * Preset the size and mtime, as there's no need
- * to invalidate the caches.
- */
- inode->i_size = fattr->size;
- inode->i_mtime = fattr->mtime.seconds;
- NFS_OLDMTIME(inode) = fattr->mtime.seconds;
- }
- nfs_refresh_inode(inode, fattr);
- dprintk("NFS: fhget(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino,
- inode->i_count);
+ nfs_fill_inode(inode, fattr);
+ dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
+ inode->i_dev, inode->i_ino, inode->i_count);
out:
return inode;
-out_bad_args:
- printk("nfs_fhget: super block is NULL\n");
- goto out;
-out_bad_attr:
- printk("nfs_fhget: getattr error = %d\n", -error);
- goto out;
out_no_inode:
- printk("nfs_fhget: iget failed\n");
+ printk("__nfs_fhget: iget failed\n");
goto out;
out_bad_id:
- printk("nfs_fhget: unexpected inode from iget\n");
+ printk("__nfs_fhget: unexpected inode from iget\n");
goto out;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov