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/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to