From: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
To: Linus Torvalds <torvalds@osdl.org>
Cc: Anton Altaparmakov <aia21@cam.ac.uk>,
vandrove@vc.cvut.cz, Andrew Morton <akpm@osdl.org>,
linware@sh.cvut.cz, fsdevel <linux-fsdevel@vger.kernel.org>,
lkml <linux-kernel@vger.kernel.org>
Subject: Re: Kernel bug: Bad page state: related to generic symlink code and mmap
Date: Fri, 19 Aug 2005 19:02:18 +0100 [thread overview]
Message-ID: <20050819180218.GE29811@parcelfarce.linux.theplanet.co.uk> (raw)
In-Reply-To: <20050819165332.GD29811@parcelfarce.linux.theplanet.co.uk>
On Fri, Aug 19, 2005 at 05:53:32PM +0100, Al Viro wrote:
> I'm taking NFS helpers to libfs.c and switching ncpfs to them. IMO that's
> better than copying the damn thing and other network filesystems might have
> the same needs eventually...
[something like this - completely untested]
* stray_page_get_link(inode, filler) - returns ERR_PTR(error) or pointer
to symlink body. Said symlink body sits in a page at offset equal to
offsetof(page, struct stray_page_link). filler() is expected to put it
at such offset. Page is cached.
* stray_page_put_link() - ->put_link() suitable for links obtained from
stray_page_get_link(). Unlike the usual pagecache-based variants, this
sucker does _not_ rely on page staying cached.
* nfs and ncpfs switched to the helpers above.
Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
----
diff -urN RC14-rc6-git10-base/fs/libfs.c current/fs/libfs.c
--- RC13-rc6-git10-base/fs/libfs.c 2005-08-10 10:37:52.000000000 -0400
+++ current/fs/libfs.c 2005-08-19 13:29:39.000000000 -0400
@@ -7,6 +7,7 @@
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/vfs.h>
+#include <linux/namei.h>
#include <asm/uaccess.h>
int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
@@ -616,6 +617,42 @@
return ret;
}
+char *stray_page_get_link(struct inode *inode, int (*filler)(struct inode *, struct page *))
+{
+ struct stray_page_symlink *p;
+ struct page *page;
+
+ page = read_cache_page(&inode->i_data, 0, (filler_t *)filler, inode);
+ if (IS_ERR(page))
+ goto read_failed;
+ if (!PageUptodate(page))
+ goto getlink_read_error;
+ p = kmap(page);
+ p->page = page;
+ return p->body;
+
+getlink_read_error:
+ page_cache_release(page);
+ page = ERR_PTR(-EIO);
+read_failed:
+ return (char *)page; /* error */
+}
+
+void stray_page_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+ char *s = nd_get_link(nd);
+ if (!IS_ERR(s)) {
+ struct stray_page_symlink *p;
+ struct page *page;
+
+ p = container_of(s, struct stray_page_symlink, body[0]);
+ page = p->page;
+
+ kunmap(page);
+ page_cache_release(page);
+ }
+}
+
EXPORT_SYMBOL(dcache_dir_close);
EXPORT_SYMBOL(dcache_dir_lseek);
EXPORT_SYMBOL(dcache_dir_open);
@@ -648,3 +685,5 @@
EXPORT_SYMBOL_GPL(simple_attr_close);
EXPORT_SYMBOL_GPL(simple_attr_read);
EXPORT_SYMBOL_GPL(simple_attr_write);
+EXPORT_SYMBOL(stray_page_get_link);
+EXPORT_SYMBOL(stray_page_put_link);
diff -urN RC13-rc6-git10-base/fs/ncpfs/inode.c current/fs/ncpfs/inode.c
--- RC13-rc6-git10-base/fs/ncpfs/inode.c 2005-06-17 15:48:29.000000000 -0400
+++ current/fs/ncpfs/inode.c 2005-08-19 13:12:01.000000000 -0400
@@ -104,7 +104,7 @@
extern struct dentry_operations ncp_root_dentry_operations;
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
-extern struct address_space_operations ncp_symlink_aops;
+extern int ncp_follow_link(struct dentry *dentry, struct nameidata *nd);
extern int ncp_symlink(struct inode*, struct dentry*, const char*);
#endif
@@ -233,8 +233,8 @@
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
static struct inode_operations ncp_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .follow_link = ncp_follow_link,
+ .put_link = stray_page_put_link,
.setattr = ncp_notify_change,
};
#endif
@@ -272,7 +272,6 @@
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &ncp_symlink_inode_operations;
- inode->i_data.a_ops = &ncp_symlink_aops;
#endif
} else {
make_bad_inode(inode);
diff -urN RC13-rc6-git10-base/fs/ncpfs/symlink.c current/fs/ncpfs/symlink.c
--- RC13-rc6-git10-base/fs/ncpfs/symlink.c 2005-06-17 15:48:29.000000000 -0400
+++ current/fs/ncpfs/symlink.c 2005-08-19 13:26:26.000000000 -0400
@@ -30,6 +30,7 @@
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/stat.h>
+#include <linux/namei.h>
#include "ncplib_kernel.h"
@@ -41,9 +42,8 @@
/* ----- read a symbolic link ------------------------------------------ */
-static int ncp_symlink_readpage(struct file *file, struct page *page)
+static int symlink_filler(struct inode *inode, struct page *page)
{
- struct inode *inode = page->mapping->host;
int error, length, len;
char *link, *rawlink;
char *buf = kmap(page);
@@ -77,6 +77,7 @@
}
len = NCP_MAX_SYMLINK_SIZE;
+ buf += offsetof(struct stray_page_symlink, body);
error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link, length, 0);
kfree(rawlink);
if (error)
@@ -96,13 +97,12 @@
return error;
}
-/*
- * symlinks can't do much...
- */
-struct address_space_operations ncp_symlink_aops = {
- .readpage = ncp_symlink_readpage,
-};
-
+int ncp_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ nd_set_link(nd, stray_page_get_link(dentry->d_inode, symlink_filler));
+ return 0;
+}
+
/* ----- create a new symbolic link -------------------------------------- */
int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
diff -urN RC13-rc6-git10-base/fs/nfs/symlink.c current/fs/nfs/symlink.c
--- RC13-rc6-git10-base/fs/nfs/symlink.c 2005-06-17 15:48:29.000000000 -0400
+++ current/fs/nfs/symlink.c 2005-08-19 13:04:44.000000000 -0400
@@ -41,7 +41,7 @@
static int nfs_symlink_filler(struct inode *inode, struct page *page)
{
- const unsigned int pgbase = offsetof(struct nfs_symlink, body);
+ const unsigned int pgbase = offsetof(struct stray_page_symlink, body);
const unsigned int pglen = PAGE_SIZE - pgbase;
int error;
@@ -63,46 +63,11 @@
static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
- struct page *page;
- struct nfs_symlink *p;
- void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode));
- if (err)
- goto read_failed;
- page = read_cache_page(&inode->i_data, 0,
- (filler_t *)nfs_symlink_filler, inode);
- if (IS_ERR(page)) {
- err = page;
- goto read_failed;
- }
- if (!PageUptodate(page)) {
- err = ERR_PTR(-EIO);
- goto getlink_read_error;
- }
- p = kmap(page);
- p->page = page;
- nd_set_link(nd, p->body);
+ char *p = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode));
+ if (!p)
+ p = stray_page_get_link(inode, nfs_symlink_filler);
+ nd_set_link(nd, p);
return 0;
-
-getlink_read_error:
- page_cache_release(page);
-read_failed:
- nd_set_link(nd, err);
- return 0;
-}
-
-static void nfs_put_link(struct dentry *dentry, struct nameidata *nd)
-{
- char *s = nd_get_link(nd);
- if (!IS_ERR(s)) {
- struct nfs_symlink *p;
- struct page *page;
-
- p = container_of(s, struct nfs_symlink, body[0]);
- page = p->page;
-
- kunmap(page);
- page_cache_release(page);
- }
}
/*
@@ -111,7 +76,7 @@
struct inode_operations nfs_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = nfs_follow_link,
- .put_link = nfs_put_link,
+ .put_link = stray_page_put_link,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
};
diff -urN RC13-rc6-git10-base/include/linux/fs.h current/include/linux/fs.h
--- RC13-rc6-git10-base/include/linux/fs.h 2005-08-10 10:37:54.000000000 -0400
+++ current/include/linux/fs.h 2005-08-19 13:26:55.000000000 -0400
@@ -1614,6 +1614,13 @@
loff_t inode_get_bytes(struct inode *inode);
void inode_set_bytes(struct inode *inode, loff_t bytes);
+struct stray_page_symlink {
+ struct page *page;
+ char body[0];
+};
+char *stray_page_get_link(struct inode *inode, int (*filler)(struct inode *, struct page *));
+void stray_page_put_link(struct dentry *dentry, struct nameidata *nd);
+
extern int vfs_readdir(struct file *, filldir_t, void *);
extern int vfs_stat(char __user *, struct kstat *);
next prev parent reply other threads:[~2005-08-19 17:59 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-08-19 11:14 Kernel bug: Bad page state: related to generic symlink code and mmap Anton Altaparmakov
2005-08-19 14:20 ` Al Viro
2005-08-19 15:44 ` Anton Altaparmakov
2005-08-19 15:58 ` Al Viro
2005-08-19 16:07 ` Linus Torvalds
2005-08-19 16:21 ` Al Viro
2005-08-19 16:21 ` Linus Torvalds
2005-08-19 16:43 ` Linus Torvalds
2005-08-19 16:53 ` Al Viro
2005-08-19 18:02 ` Al Viro [this message]
2005-08-19 18:00 ` Christoph Hellwig
2005-08-19 19:38 ` Al Viro
2005-08-19 19:41 ` Matthew Wilcox
2005-08-19 19:43 ` Al Viro
2005-08-19 21:19 ` Christoph Hellwig
2005-08-19 20:35 ` Linus Torvalds
2005-08-19 21:20 ` Anton Altaparmakov
2005-08-19 21:35 ` Linus Torvalds
2005-08-19 21:42 ` Al Viro
2005-08-19 19:16 ` Mika Penttilä
2005-08-19 19:40 ` Al Viro
2005-08-19 19:40 ` Al Viro
2005-08-19 19:50 ` Mika Penttilä
2005-08-19 19:50 ` Mika Penttilä
2005-08-19 20:46 ` Anton Altaparmakov
2005-08-19 20:55 ` Linus Torvalds
2005-08-19 21:39 ` Anton Altaparmakov
2005-08-19 22:04 ` Linus Torvalds
2005-08-19 23:15 ` Al Viro
2005-08-19 23:17 ` Al Viro
2005-08-20 1:08 ` Linus Torvalds
2005-08-20 1:15 ` Al Viro
2005-08-20 12:49 ` Anton Altaparmakov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20050819180218.GE29811@parcelfarce.linux.theplanet.co.uk \
--to=viro@parcelfarce.linux.theplanet.co.uk \
--cc=aia21@cam.ac.uk \
--cc=akpm@osdl.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linware@sh.cvut.cz \
--cc=torvalds@osdl.org \
--cc=vandrove@vc.cvut.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.