patch-2.4.0-test12 linux/fs/nfs/inode.c

Next file: linux/fs/nfs/nfs3proc.c
Previous file: linux/fs/nfs/file.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test11/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
@@ -39,7 +39,7 @@
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
 
-static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
+static struct inode * __nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *);
 void nfs_zap_caches(struct inode *);
 static void nfs_invalidate_inode(struct inode *);
 
@@ -222,13 +222,10 @@
 		return NULL;
 	}
 
-	inode = __nfs_fhget(sb, &fattr);
+	inode = __nfs_fhget(sb, rootfh, &fattr);
 	return inode;
 }
 
-extern struct nfs_fh *nfs_fh_alloc(void);
-extern void nfs_fh_free(struct nfs_fh *p);
-
 /*
  * The way this works is that the mount process passes a structure
  * in the data argument which contains the server's IP address
@@ -242,7 +239,7 @@
 	struct nfs_server	*server;
 	struct rpc_xprt		*xprt = NULL;
 	struct rpc_clnt		*clnt = NULL;
-	struct nfs_fh		*root = &data->root, *root_fh, fh;
+	struct nfs_fh		*root = &data->root, fh;
 	struct inode		*root_inode = NULL;
 	unsigned int		authflavor;
 	struct sockaddr_in	srvaddr;
@@ -365,16 +362,10 @@
 	 * Keep the super block locked while we try to get 
 	 * the root fh attributes.
 	 */
-	root_fh = nfs_fh_alloc();
-	if (!root_fh)
-		goto out_no_fh;
-	memcpy((u8*)root_fh, (u8*)root, sizeof(*root));
-
 	/* Did getting the root inode fail? */
 	if (!(root_inode = nfs_get_root(sb, root))
 	    && (data->flags & NFS_MOUNT_VER3)) {
 		data->flags &= ~NFS_MOUNT_VER3;
-		nfs_fh_free(root_fh);
 		rpciod_down();
 		rpc_shutdown_client(server->client);
 		goto nfsv3_try_again;
@@ -387,7 +378,6 @@
 		goto out_no_root;
 
 	sb->s_root->d_op = &nfs_dentry_operations;
-	sb->s_root->d_fsdata = root_fh;
 
 	/* Get some general file system info */
         if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
@@ -462,8 +452,6 @@
 out_no_root:
 	printk("nfs_read_super: get root inode failed\n");
 	iput(root_inode);
-	nfs_fh_free(root_fh);
-out_no_fh:
 	rpciod_down();
 	goto out_shutdown;
 
@@ -507,7 +495,7 @@
 	struct nfs_fsinfo res;
 	int error;
 
-	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
+	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
 	buf->f_type = NFS_SUPER_MAGIC;
 	if (error < 0)
 		goto out_err;
@@ -532,43 +520,6 @@
 }
 
 /*
- * Free all unused dentries in an inode's alias list.
- *
- * Subtle note: we have to be very careful not to cause
- * any IO operations with the stale dentries, as this
- * could cause file corruption. But since the dentry
- * count is 0 and all pending IO for a dentry has been
- * flushed when the count went to 0, we're safe here.
- * Also returns the number of unhashed dentries
- */
-static int
-nfs_free_dentries(struct inode *inode)
-{
-	struct list_head *tmp, *head;
-	int unhashed;
-
-	if (S_ISDIR(inode->i_mode)) {
-		struct dentry *dentry = d_find_alias(inode);
-		if (dentry) {
-			shrink_dcache_parent(dentry);
-			dput(dentry);
-		}
-	}
-	d_prune_aliases(inode);
-	spin_lock(&dcache_lock);
-	head = &inode->i_dentry;
-	tmp = head;
-	unhashed = 0;
-	while ((tmp = tmp->next) != head) {
-		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
-		if (list_empty(&dentry->d_hash))
-			unhashed++;
-	}
-	spin_unlock(&dcache_lock);
-	return unhashed;
-}
-
-/*
  * Invalidate the local caches
  */
 void
@@ -600,7 +551,7 @@
  * Fill in inode information from the fattr.
  */
 static void
-nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
+nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
 	/*
 	 * Check whether the mode has been set, as we only want to
@@ -638,10 +589,16 @@
 		NFS_CACHE_ISIZE(inode) = fattr->size;
 		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
 		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+		memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh));
 	}
 	nfs_refresh_inode(inode, fattr);
 }
 
+struct nfs_find_desc {
+	struct nfs_fh		*fh;
+	struct nfs_fattr	*fattr;
+};
+
 /*
  * In NFSv3 we can have 64bit inode numbers. In order to support
  * this, and re-exported directories (also seen in NFSv2)
@@ -651,43 +608,38 @@
 static int
 nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
 {
-	struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+	struct nfs_find_desc	*desc = (struct nfs_find_desc *)opaque;
+	struct nfs_fh		*fh = desc->fh;
+	struct nfs_fattr	*fattr = desc->fattr;
+
 	if (NFS_FSID(inode) != fattr->fsid)
 		return 0;
 	if (NFS_FILEID(inode) != fattr->fileid)
 		return 0;
+	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0)
+		return 0;
 	return 1;
 }
 
-static int
-nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
+int
+nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
-	int unhashed;
-	int is_stale = 0;
+	/* Empty inodes are not stale */
+	if (!inode->i_mode)
+		return 0;
 
-	if (inode->i_mode &&
-	    (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
-		is_stale = 1;
+	if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+		return 1;
 
 	if (is_bad_inode(inode))
-		is_stale = 1;
-
-	/*
-	 * If the inode seems stale, free up cached dentries.
-	 */
-	unhashed = nfs_free_dentries(inode);
+		return 1;
 
-	/* Assume we're holding an i_count
-	 *
-	 * NB: sockets sometimes have volatile file handles
-	 *     don't invalidate their inodes even if all dentries are
-	 *     unhashed.
-	 */
-	if (unhashed && atomic_read(&inode->i_count) == unhashed + 1
-	    && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
-		is_stale = 1;
+	/* Has the filehandle changed? If so is the old one stale? */
+	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
+	    __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
+		return 1;
 
-	return is_stale;
+	return 0;
 }
 
 /*
@@ -696,8 +648,6 @@
  * 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,
@@ -708,44 +658,16 @@
 	dprintk("NFS: nfs_fhget(%s/%s fileid=%Ld)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(long long)fattr->fileid);
-
-	/* Install the file handle in the dentry */
-	memcpy(dentry->d_fsdata, fhandle, sizeof(struct nfs_fh));
-
-#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) ||
-	    (dentry->d_name.len == 9 &&
-	     memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
-		struct inode *inode = new_inode(sb);
-		if (!inode)
-			goto out;
-		inode->i_ino = nfs_fattr_to_ino_t(fattr);
-		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);
+	return __nfs_fhget(sb, fhandle, fattr);
 }
 
 /*
  * Look up the inode by super block and fattr->fileid.
- *
- * Note carefully the special handling of busy inodes (i_count > 1).
- * 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.
  */
 static struct inode *
-__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
+__nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
+	struct nfs_find_desc desc = { fh, fattr };
 	struct inode *inode = NULL;
 	unsigned long ino;
 
@@ -759,33 +681,13 @@
 
 	ino = nfs_fattr_to_ino_t(fattr);
 
-	while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
-
-		/*
-		 * Check for busy inodes, and attempt to get rid of any
-		 * unused local references. If successful, we release the
-		 * inode and try again.
-		 *
-		 * Note that the busy test uses the values in the fattr,
-		 * as the inode may have become a different object.
-		 * (We can probably handle modes changes here, too.)
-		 */
-		if (!nfs_inode_is_stale(inode,fattr))
-			break;
-
-		dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
-		       inode->i_ino, atomic_read(&inode->i_count));
-		nfs_zap_caches(inode);
-		remove_inode_hash(inode);
-		iput(inode);
-	}
-
-	if (!inode)
+	if (!(inode = iget4(sb, ino, nfs_find_actor, &desc)))
 		goto out_no_inode;
 
-	nfs_fill_inode(inode, fattr);
-	dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
-		inode->i_dev, inode->i_ino, atomic_read(&inode->i_count));
+	nfs_fill_inode(inode, fh, fattr);
+	dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode),
+		atomic_read(&inode->i_count));
 
 out:
 	return inode;
@@ -820,7 +722,7 @@
 	if (error)
 		goto out;
 
-	error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
+	error = NFS_PROTO(inode)->setattr(inode, &fattr, attr);
 	if (error)
 		goto out;
 	/*
@@ -872,7 +774,8 @@
 int
 nfs_revalidate(struct dentry *dentry)
 {
-	return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+	struct inode *inode = dentry->d_inode;
+	return nfs_revalidate_inode(NFS_SERVER(inode), inode);
 }
 
 /*
@@ -913,18 +816,16 @@
  * the cached attributes have to be refreshed.
  */
 int
-__nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	struct inode	*inode = dentry->d_inode;
 	int		 status = 0;
 	struct nfs_fattr fattr;
 
-	dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name,
-		inode->i_ino);
+	dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode));
 
 	lock_kernel();
-	if (!inode || is_bad_inode(inode)) {
+	if (!inode || is_bad_inode(inode) || NFS_STALE(inode)) {
 		unlock_kernel();
 		return -ESTALE;
 	}
@@ -936,55 +837,35 @@
 			return status;
 		}
 		if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
-			unlock_kernel();
-			return 0;
+			status = NFS_STALE(inode) ? -ESTALE : 0;
+			goto out_nowait;
 		}
 	}
 	NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
 
-	status = NFS_PROTO(inode)->getattr(dentry, &fattr);
+	status = NFS_PROTO(inode)->getattr(inode, &fattr);
 	if (status) {
-		struct dentry *dir = dentry->d_parent;
-		struct inode *dir_i = dir->d_inode;
-		int error;
-		u32 *fh;
-		struct nfs_fh fhandle;
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
-			 dir->d_name.name, dentry->d_name.name,
-			 inode->i_ino, status);
-		if (status != -ESTALE)
-			goto out;
-		/*
-		 * A "stale filehandle" error ... show the current fh
-		 * and find out what the filehandle should be.
-		 */
-		fh = (u32 *) NFS_FH(dentry)->data;
-		dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
-			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
-		error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name,
-						 &fhandle, &fattr);
-		if (error) {
-			dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
-			goto out;
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
+			 inode->i_dev, (long long)NFS_FILEID(inode), status);
+		if (status == -ESTALE) {
+			NFS_FLAGS(inode) |= NFS_INO_STALE;
+			remove_inode_hash(inode);
 		}
-		fh = (u32 *) fhandle.data;
-		dfprintk(PAGECACHE, "            %08x%08x%08x%08x%08x%08x%08x%08x\n",
-			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
 		goto out;
 	}
 
 	status = nfs_refresh_inode(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
-			dentry->d_parent->d_name.name,
-			dentry->d_name.name, inode->i_ino, status);
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n",
+			 inode->i_dev, (long long)NFS_FILEID(inode), status);
 		goto out;
 	}
-	dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
+	dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n",
+		inode->i_dev, (long long)NFS_FILEID(inode));
 out:
 	NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
 	wake_up(&inode->i_wait);
+ out_nowait:
 	unlock_kernel();
 	return status;
 }
@@ -1165,8 +1046,6 @@
  */
 static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, FS_ODD_RENAME);
 
-extern int nfs_init_fhcache(void);
-extern void nfs_destroy_fhcache(void);
 extern int nfs_init_nfspagecache(void);
 extern void nfs_destroy_nfspagecache(void);
 extern int nfs_init_readpagecache(void);
@@ -1180,10 +1059,6 @@
 {
 	int err;
 
-	err = nfs_init_fhcache();
-	if (err)
-		return err;
-
 	err = nfs_init_nfspagecache();
 	if (err)
 		return err;
@@ -1218,7 +1093,6 @@
 {
 	nfs_destroy_readpagecache();
 	nfs_destroy_nfspagecache();
-	nfs_destroy_fhcache();
 #ifdef CONFIG_PROC_FS
 	rpc_proc_unregister("nfs");
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)