diff options
author | Brian Behlendorf <[email protected]> | 2016-01-14 13:25:10 -0500 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2016-01-29 09:52:13 -0800 |
commit | b3c9e2caf570d0c7093de33fb5280541865b32d9 (patch) | |
tree | 06453021d6d28fd9f4dd045cfac647e3aa5a1989 /module/zfs | |
parent | f00a5734f61347446fd5175801b03ad45373b8cf (diff) |
Linux 4.5 compat: get_link() / put_link()
The follow_link() interface was retired in favor of get_link().
In the process of phasing in get_link() the Linux kernel went
through two different versions. The first of which depended
on put_link() and the final version on a delayed done function.
- Improved configure checks for .follow_link, .get_link, .put_link.
- Interfaces checked from newest to oldest.
- Strict checking for each possible known interface.
- Configure fails when no known interface is available.
- Both versions .get_link are detected and supported as well
two previous versions of .follow_link.
Signed-off-by: Brian Behlendorf <[email protected]>
Signed-off-by: Tim Chase <[email protected]>
Signed-off-by: Chunwei Chen <[email protected]>
Issue #4228
Diffstat (limited to 'module/zfs')
-rw-r--r-- | module/zfs/zpl_inode.c | 125 |
1 files changed, 92 insertions, 33 deletions
diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c index e0e8ee3ac..bd0d5129c 100644 --- a/module/zfs/zpl_inode.c +++ b/module/zfs/zpl_inode.c @@ -339,26 +339,42 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name) return (error); } -#ifdef HAVE_FOLLOW_LINK_NAMEIDATA -static void * -zpl_follow_link(struct dentry *dentry, struct nameidata *nd) -#else -const char * -zpl_follow_link(struct dentry *dentry, void **symlink_cookie) +#if defined(HAVE_PUT_LINK_COOKIE) +static void +zpl_put_link(struct inode *unused, void *cookie) +{ + kmem_free(cookie, MAXPATHLEN); +} +#elif defined(HAVE_PUT_LINK_NAMEIDATA) +static void +zpl_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) +{ + const char *link = nd_get_link(nd); + + if (!IS_ERR(link)) + kmem_free(link, MAXPATHLEN); +} +#elif defined(HAVE_PUT_LINK_DELAYED) +static void +zpl_put_link(void *ptr) +{ + kmem_free(ptr, MAXPATHLEN); +} #endif + +static int +zpl_get_link_common(struct dentry *dentry, struct inode *ip, char **link) { + fstrans_cookie_t cookie; cred_t *cr = CRED(); - struct inode *ip = dentry->d_inode; struct iovec iov; uio_t uio; - char *link; int error; - fstrans_cookie_t cookie; crhold(cr); - + *link = NULL; iov.iov_len = MAXPATHLEN; - iov.iov_base = link = kmem_zalloc(MAXPATHLEN, KM_SLEEP); + iov.iov_base = kmem_zalloc(MAXPATHLEN, KM_SLEEP); uio.uio_iov = &iov; uio.uio_iovcnt = 1; @@ -369,41 +385,78 @@ zpl_follow_link(struct dentry *dentry, void **symlink_cookie) cookie = spl_fstrans_mark(); error = -zfs_readlink(ip, &uio, cr); spl_fstrans_unmark(cookie); - - if (error) - kmem_free(link, MAXPATHLEN); - crfree(cr); -#ifdef HAVE_FOLLOW_LINK_NAMEIDATA if (error) - nd_set_link(nd, ERR_PTR(error)); + kmem_free(iov.iov_base, MAXPATHLEN); else - nd_set_link(nd, link); + *link = iov.iov_base; - return (NULL); -#else + return (error); +} + +#if defined(HAVE_GET_LINK_DELAYED) +const char * +zpl_get_link(struct dentry *dentry, struct inode *inode, + struct delayed_call *done) +{ + char *link = NULL; + int error; + + if (!dentry) + return (ERR_PTR(-ECHILD)); + + error = zpl_get_link_common(dentry, inode, &link); if (error) return (ERR_PTR(error)); - else - return (*symlink_cookie = link); -#endif + + set_delayed_call(done, zpl_put_link, link); + + return (link); } +#elif defined(HAVE_GET_LINK_COOKIE) +const char * +zpl_get_link(struct dentry *dentry, struct inode *inode, void **cookie) +{ + char *link = NULL; + int error; -#ifdef HAVE_PUT_LINK_NAMEIDATA -static void -zpl_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) + if (!dentry) + return (ERR_PTR(-ECHILD)); + + error = zpl_get_link_common(dentry, inode, &link); + if (error) + return (ERR_PTR(error)); + + return (*cookie = link); +} +#elif defined(HAVE_FOLLOW_LINK_COOKIE) +const char * +zpl_follow_link(struct dentry *dentry, void **cookie) { - const char *link = nd_get_link(nd); + char *link = NULL; + int error; - if (!IS_ERR(link)) - kmem_free(link, MAXPATHLEN); + error = zpl_get_link_common(dentry, dentry->d_inode, &link); + if (error) + return (ERR_PTR(error)); + + return (*cookie = link); } -#else -static void -zpl_put_link(struct inode *unused, void *symlink_cookie) +#elif defined(HAVE_FOLLOW_LINK_NAMEIDATA) +static void * +zpl_follow_link(struct dentry *dentry, struct nameidata *nd) { - kmem_free(symlink_cookie, MAXPATHLEN); + char *link = NULL; + int error; + + error = zpl_get_link_common(dentry, dentry->d_inode, &link); + if (error) + nd_set_link(nd, ERR_PTR(error)); + else + nd_set_link(nd, link); + + return (NULL); } #endif @@ -591,8 +644,14 @@ const struct inode_operations zpl_dir_inode_operations = { const struct inode_operations zpl_symlink_inode_operations = { .readlink = generic_readlink, +#if defined(HAVE_GET_LINK_DELAYED) || defined(HAVE_GET_LINK_COOKIE) + .get_link = zpl_get_link, +#elif defined(HAVE_FOLLOW_LINK_COOKIE) || defined(HAVE_FOLLOW_LINK_NAMEIDATA) .follow_link = zpl_follow_link, +#endif +#if defined(HAVE_PUT_LINK_COOKIE) || defined(HAVE_PUT_LINK_NAMEIDATA) .put_link = zpl_put_link, +#endif .setattr = zpl_setattr, .getattr = zpl_getattr, .setxattr = generic_setxattr, |