diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-29 15:58:39 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-30 13:01:03 -0500 |
commit | fceef393a538134f03b778c5d2519e670269342f (patch) | |
tree | cd43c9afdc07852d286965ad4d11772f6c275d1a /fs/namei.c | |
parent | cd3417c8fc9504cc1afe944515f338aff9ec286b (diff) | |
download | lwn-fceef393a538134f03b778c5d2519e670269342f.tar.gz lwn-fceef393a538134f03b778c5d2519e670269342f.zip |
switch ->get_link() to delayed_call, kill ->put_link()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 63 |
1 files changed, 26 insertions, 37 deletions
diff --git a/fs/namei.c b/fs/namei.c index 8f517888c3e1..3c909aebef70 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -505,13 +505,13 @@ struct nameidata { int total_link_count; struct saved { struct path link; - void *cookie; + struct delayed_call done; const char *name; - struct inode *inode; unsigned seq; } *stack, internal[EMBEDDED_LEVELS]; struct filename *name; struct nameidata *saved; + struct inode *link_inode; unsigned root_seq; int dfd; }; @@ -592,11 +592,8 @@ static void drop_links(struct nameidata *nd) int i = nd->depth; while (i--) { struct saved *last = nd->stack + i; - struct inode *inode = last->inode; - if (last->cookie && inode->i_op->put_link) { - inode->i_op->put_link(inode, last->cookie); - last->cookie = NULL; - } + do_delayed_call(&last->done); + clear_delayed_call(&last->done); } } @@ -858,9 +855,7 @@ void nd_jump_link(struct path *path) static inline void put_link(struct nameidata *nd) { struct saved *last = nd->stack + --nd->depth; - struct inode *inode = last->inode; - if (last->cookie && inode->i_op->put_link) - inode->i_op->put_link(inode, last->cookie); + do_delayed_call(&last->done); if (!(nd->flags & LOOKUP_RCU)) path_put(&last->link); } @@ -892,7 +887,7 @@ static inline int may_follow_link(struct nameidata *nd) return 0; /* Allowed if owner and follower match. */ - inode = nd->stack[0].inode; + inode = nd->link_inode; if (uid_eq(current_cred()->fsuid, inode->i_uid)) return 0; @@ -983,7 +978,7 @@ const char *get_link(struct nameidata *nd) { struct saved *last = nd->stack + nd->depth - 1; struct dentry *dentry = last->link.dentry; - struct inode *inode = last->inode; + struct inode *inode = nd->link_inode; int error; const char *res; @@ -1004,23 +999,21 @@ const char *get_link(struct nameidata *nd) nd->last_type = LAST_BIND; res = inode->i_link; if (!res) { + const char * (*get)(struct dentry *, struct inode *, + struct delayed_call *); + get = inode->i_op->get_link; if (nd->flags & LOOKUP_RCU) { - res = inode->i_op->get_link(NULL, inode, - &last->cookie); + res = get(NULL, inode, &last->done); if (res == ERR_PTR(-ECHILD)) { if (unlikely(unlazy_walk(nd, NULL, 0))) return ERR_PTR(-ECHILD); - res = inode->i_op->get_link(dentry, inode, - &last->cookie); + res = get(dentry, inode, &last->done); } } else { - res = inode->i_op->get_link(dentry, inode, - &last->cookie); + res = get(dentry, inode, &last->done); } - if (IS_ERR_OR_NULL(res)) { - last->cookie = NULL; + if (IS_ERR_OR_NULL(res)) return res; - } } if (*res == '/') { if (nd->flags & LOOKUP_RCU) { @@ -1699,8 +1692,8 @@ static int pick_link(struct nameidata *nd, struct path *link, last = nd->stack + nd->depth++; last->link = *link; - last->cookie = NULL; - last->inode = inode; + clear_delayed_call(&last->done); + nd->link_inode = inode; last->seq = seq; return 1; } @@ -4508,26 +4501,25 @@ EXPORT_SYMBOL(readlink_copy); */ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) { - void *cookie; + DEFINE_DELAYED_CALL(done); struct inode *inode = d_inode(dentry); const char *link = inode->i_link; int res; if (!link) { - link = inode->i_op->get_link(dentry, inode, &cookie); + link = inode->i_op->get_link(dentry, inode, &done); if (IS_ERR(link)) return PTR_ERR(link); } res = readlink_copy(buffer, buflen, link); - if (inode->i_op->put_link) - inode->i_op->put_link(inode, cookie); + do_delayed_call(&done); return res; } EXPORT_SYMBOL(generic_readlink); /* get the link contents into pagecache */ const char *page_get_link(struct dentry *dentry, struct inode *inode, - void **cookie) + struct delayed_call *callback) { char *kaddr; struct page *page; @@ -4546,7 +4538,7 @@ const char *page_get_link(struct dentry *dentry, struct inode *inode, if (IS_ERR(page)) return (char*)page; } - *cookie = page; + set_delayed_call(callback, page_put_link, page); BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); kaddr = page_address(page); nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1); @@ -4555,21 +4547,19 @@ const char *page_get_link(struct dentry *dentry, struct inode *inode, EXPORT_SYMBOL(page_get_link); -void page_put_link(struct inode *unused, void *cookie) +void page_put_link(void *arg) { - struct page *page = cookie; - page_cache_release(page); + put_page(arg); } EXPORT_SYMBOL(page_put_link); int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) { - void *cookie = NULL; + DEFINE_DELAYED_CALL(done); int res = readlink_copy(buffer, buflen, page_get_link(dentry, d_inode(dentry), - &cookie)); - if (cookie) - page_put_link(NULL, cookie); + &done)); + do_delayed_call(&done); return res; } EXPORT_SYMBOL(page_readlink); @@ -4619,6 +4609,5 @@ EXPORT_SYMBOL(page_symlink); const struct inode_operations page_symlink_inode_operations = { .readlink = generic_readlink, .get_link = page_get_link, - .put_link = page_put_link, }; EXPORT_SYMBOL(page_symlink_inode_operations); |