linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Anton Altaparmakov <aia21@cam.ac.uk>
To: Linus Torvalds <torvalds@osdl.org>
Cc: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>,
	Christoph Hellwig <hch@infradead.org>,
	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 22:20:24 +0100 (BST)	[thread overview]
Message-ID: <Pine.LNX.4.60.0508192214240.7312@hermes-1.csi.cam.ac.uk> (raw)
In-Reply-To: <Pine.LNX.4.58.0508191323250.3412@g5.osdl.org>

On Fri, 19 Aug 2005, Linus Torvalds wrote:
> The one thing that strikes me is that we might actually have less pain if
> we just changed the calling convention for follow_link/put_link slightly
> instead of creating a new library function. The existing "page cache"  
> thing really _does_ work very well, and would work fine for NFS and ncpfs
> too, if we just allowed an extra cookie to be passed along from
> "follow_link()" to "put_link()".
> 
> A patch like this (totally untested, and you'd need to update any
> filesystems that don't use the regular page_follow_link interface) would
> seem to clean up the mess nicely.. The basic change is that follow_link() 
> returns a error-pointer cookie instead of just zero or error, and that is 
> passed into put_link().
> 
> That simple calling convention change solves all problems. It so _happens_ 
> that any old binary code also continues to work (the cookie will be zero, 
> and put_link will ignore it), so it shouldn't even break any unconverted 
> stuff (unless they mix using their own functions _and_ using the helpher 
> functions, which is of course possible).
> 
> The "shouldn't break nonconverted filesystems" makes me think this is a 
> safe change. Comments?
> 
> NOTE NOTE NOTE! Let me say again that it's untested. It might not break 
> nonconverted filesystems, but it equally well migth break even the 
> converted ones ;)
> 
> 		Linus
> 
> ----
> diff --git a/fs/namei.c b/fs/namei.c
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -501,6 +501,7 @@ struct path {
>  static inline int __do_follow_link(struct path *path, struct nameidata *nd)
>  {
>  	int error;
> +	void *cookie;
>  	struct dentry *dentry = path->dentry;
>  
>  	touch_atime(path->mnt, dentry);
> @@ -508,13 +509,15 @@ static inline int __do_follow_link(struc
>  
>  	if (path->mnt == nd->mnt)
>  		mntget(path->mnt);
> -	error = dentry->d_inode->i_op->follow_link(dentry, nd);
> -	if (!error) {
> +	cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
> +	error = PTR_ERR(cookie);
> +	if (!IS_ERR(cookie)) {
>  		char *s = nd_get_link(nd);
> +		error = 0;
>  		if (s)
>  			error = __vfs_follow_link(nd, s);
>  		if (dentry->d_inode->i_op->put_link)
> -			dentry->d_inode->i_op->put_link(dentry, nd);
> +			dentry->d_inode->i_op->put_link(dentry, nd, cookie);
>  	}
>  	dput(dentry);
>  	mntput(path->mnt);
> @@ -2345,14 +2348,17 @@ int generic_readlink(struct dentry *dent
>  {
>  	struct nameidata nd;
>  	int res;
> +	void *cookie;
> +
>  	nd.depth = 0;
> -	res = dentry->d_inode->i_op->follow_link(dentry, &nd);
> -	if (!res) {
> +	cookie = dentry->d_inode->i_op->follow_link(dentry, &nd);
> +	if (!IS_ERR(cookie)) {
>  		res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
>  		if (dentry->d_inode->i_op->put_link)
> -			dentry->d_inode->i_op->put_link(dentry, &nd);
> +			dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
> +		cookie = ERR_PTR(0);

You are throwing away the error return from vfs_readlink().  I suspect you 
wanted:

+		cookie = ERR_PTR(res);

>  	}
> -	return res;
> +	return PTR_ERR(cookie);
>  }
>  
>  int vfs_follow_link(struct nameidata *nd, const char *link)
> @@ -2395,23 +2401,19 @@ int page_readlink(struct dentry *dentry,
>  	return res;
>  }
>  
> -int page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
> +void *page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
>  {
>  	struct page *page;
>  	nd_set_link(nd, page_getlink(dentry, &page));
> -	return 0;
> +	return page;
>  }
>  
> -void page_put_link(struct dentry *dentry, struct nameidata *nd)
> +void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
>  {
>  	if (!IS_ERR(nd_get_link(nd))) {
> -		struct page *page;
> -		page = find_get_page(dentry->d_inode->i_mapping, 0);
> -		if (!page)
> -			BUG();
> +		struct page *page = cookie;
>  		kunmap(page);
>  		page_cache_release(page);
> -		page_cache_release(page);
>  	}
>  }
>  
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -993,8 +993,8 @@ struct inode_operations {
>  	int (*rename) (struct inode *, struct dentry *,
>  			struct inode *, struct dentry *);
>  	int (*readlink) (struct dentry *, char __user *,int);
> -	int (*follow_link) (struct dentry *, struct nameidata *);
> -	void (*put_link) (struct dentry *, struct nameidata *);
> +	void * (*follow_link) (struct dentry *, struct nameidata *);
> +	void (*put_link) (struct dentry *, struct nameidata *, void *);
>  	void (*truncate) (struct inode *);
>  	int (*permission) (struct inode *, int, struct nameidata *);
>  	int (*setattr) (struct dentry *, struct iattr *);
> @@ -1602,8 +1602,8 @@ extern struct file_operations generic_ro
>  extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
>  extern int vfs_follow_link(struct nameidata *, const char *);
>  extern int page_readlink(struct dentry *, char __user *, int);
> -extern int page_follow_link_light(struct dentry *, struct nameidata *);
> -extern void page_put_link(struct dentry *, struct nameidata *);
> +extern void *page_follow_link_light(struct dentry *, struct nameidata *);
> +extern void page_put_link(struct dentry *, struct nameidata *, void *);
>  extern int page_symlink(struct inode *inode, const char *symname, int len);
>  extern struct inode_operations page_symlink_inode_operations;
>  extern int generic_readlink(struct dentry *, char __user *, int);

Best regards,

	Anton
-- 
Anton Altaparmakov <aia21 at cam.ac.uk> (replace at with @)
Unix Support, Computing Service, University of Cambridge, CB2 3QH, UK
Linux NTFS maintainer / IRC: #ntfs on irc.freenode.net
WWW: http://linux-ntfs.sf.net/ & http://www-stu.christs.cam.ac.uk/~aia21/

  reply	other threads:[~2005-08-19 21:20 UTC|newest]

Thread overview: 31+ 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
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 [this message]
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: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=Pine.LNX.4.60.0508192214240.7312@hermes-1.csi.cam.ac.uk \
    --to=aia21@cam.ac.uk \
    --cc=akpm@osdl.org \
    --cc=hch@infradead.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 \
    --cc=viro@parcelfarce.linux.theplanet.co.uk \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).