patch-2.3.30 linux/fs/nfs/symlink.c

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

diff -u --recursive --new-file v2.3.29/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c
@@ -46,126 +46,101 @@
 	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL,			/* smap */
 	NULL			/* revalidate */
 };
 
 /* Symlink caching in the page cache is even more simplistic
  * and straight-forward than readdir caching.
  */
-static struct page *try_to_get_symlink_page(struct dentry *dentry, struct inode *inode)
+static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
 {
 	struct nfs_readlinkargs rl_args;
-	struct page *page, **hash, *page_cache;
-
-	page = NULL;
-	page_cache = page_cache_alloc();
-	if (!page_cache)
-		goto out;
-
-	hash = page_hash(&inode->i_data, 0);
-repeat:
-	page = __find_lock_page(&inode->i_data, 0, hash);
-	if (page) {
-		page_cache_free(page_cache);
-		goto unlock_out;
-	}
-
-	page = page_cache;
-	if (add_to_page_cache_unique(page, &inode->i_data, 0, hash)) {
-		page_cache_release(page);
-		goto repeat;
-	}
-
 	kmap(page);
-
 	/* We place the length at the beginning of the page,
 	 * in host byte order, followed by the string.  The
 	 * XDR response verification will NULL terminate it.
 	 */
 	rl_args.fh = NFS_FH(dentry);
-	rl_args.buffer = (const void *)page_address(page_cache);
-	if (rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
+	rl_args.buffer = (const void *)page_address(page);
+	if (rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
 		     &rl_args, NULL, 0) < 0)
 		goto error;
 	SetPageUptodate(page);
-unlock_out:
 	kunmap(page);
 	UnlockPage(page);
-out:
-	return page;
+	return 0;
 
 error:
 	SetPageError(page);
-	goto unlock_out;
+	kunmap(page);
+	UnlockPage(page);
+	return -EIO;
 }
 
-static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+static char *nfs_getlink(struct dentry *dentry, struct page **ppage)
 {
 	struct inode *inode = dentry->d_inode;
 	struct page *page;
-	u32 *p, len;
+	u32 *p;
 
 	/* Caller revalidated the directory inode already. */
-	page = find_get_page(&inode->i_data, 0);
-	if (!page)
-		goto no_readlink_page;
+	page = read_cache_page(&inode->i_data, 0,
+				(filler_t *)nfs_symlink_filler, dentry);
+	if (IS_ERR(page))
+		goto read_failed;
 	if (!Page_Uptodate(page))
-		goto readlink_read_error;
-success:
+		goto followlink_read_error;
+	*ppage = page;
 	p = (u32 *) kmap(page);
-	len = *p++;
+	return (char*)(p+1);
+		
+followlink_read_error:
+	page_cache_release(page);
+	return ERR_PTR(-EIO);
+read_failed:
+	return (char*)page;
+}
+
+static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+	struct page *page = NULL;
+	u32 len;
+	char *s = nfs_getlink(dentry, &page);
+	UPDATE_ATIME(dentry->d_inode);
+
+	len = PTR_ERR(s);
+	if (IS_ERR(s))
+		goto out;
+
+	len = strlen(s);
 	if (len > buflen)
 		len = buflen;
-	copy_to_user(buffer, p, len);
+	copy_to_user(buffer, s, len);
 	kunmap(page);
 	page_cache_release(page);
+out:
 	return len;
-
-no_readlink_page:
-	page = try_to_get_symlink_page(dentry, inode);
-	if (!page)
-		goto no_page;
-	if (Page_Uptodate(page))
-		goto success;
-readlink_read_error:
-	page_cache_release(page);
-no_page:
-	return -EIO;
 }
 
 static struct dentry *
 nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
 {
 	struct dentry *result;
-	struct inode *inode = dentry->d_inode;
-	struct page *page;
-	u32 *p;
+	struct page *page = NULL;
+	char *s = nfs_getlink(dentry, &page);
+	UPDATE_ATIME(dentry->d_inode);
+
+	if (IS_ERR(s))
+		goto fail;
+
+	result = lookup_dentry(s, base, follow);
 
-	/* Caller revalidated the directory inode already. */
-	page = find_get_page(&inode->i_data, 0);
-	if (!page)
-		goto no_followlink_page;
-	if (!Page_Uptodate(page))
-		goto followlink_read_error;
-success:
-	p = (u32 *) kmap(page);
-	result = lookup_dentry((char *) (p + 1), base, follow);
 	kunmap(page);
 	page_cache_release(page);
 	return result;
 
-no_followlink_page:
-	page = try_to_get_symlink_page(dentry, inode);
-	if (!page)
-		goto no_page;
-	if (Page_Uptodate(page))
-		goto success;
-followlink_read_error:
-	page_cache_release(page);
-no_page:
-	return ERR_PTR(-EIO);
+fail:
+	return (struct dentry *)s;
 }

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