X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Fsymlink.c;h=b58a5d34a6184c2f4a527e1f4c8448e81d8e5d5d;hb=710e1a34bada840db26198d8333d6477e536ef86;hp=3c9d646d985520724e3536feda0822fd103fd65c;hpb=93acd158c57c4c5d0fc751d46741231490c04707;p=fs%2Flustre-release.git diff --git a/lustre/llite/symlink.c b/lustre/llite/symlink.c index 3c9d646..b58a5d3 100644 --- a/lustre/llite/symlink.c +++ b/lustre/llite/symlink.c @@ -23,16 +23,20 @@ #include #include #include +#include #define DEBUG_SUBSYSTEM S_LLITE -#include +#include +#include "llite_internal.h" static int ll_readlink_internal(struct inode *inode, struct ptlrpc_request **request, char **symname) { struct ll_inode_info *lli = ll_i2info(inode); struct ll_sb_info *sbi = ll_i2sbi(inode); - int rc, symlen = inode->i_size + 1; + int rc, symlen = i_size_read(inode) + 1; + struct mdt_body *body; + struct obd_capa *oc; ENTRY; *request = NULL; @@ -43,21 +47,57 @@ static int ll_readlink_internal(struct inode *inode, RETURN(0); } - rc = mdc_getattr(&sbi->ll_mdc_conn, inode->i_ino, S_IFLNK, - OBD_MD_LINKNAME, symlen, request); + oc = ll_mdscapa_get(inode); + rc = md_getattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, + OBD_MD_LINKNAME, symlen, request); + capa_put(oc); if (rc) { - CERROR("inode %lu: rc = %d\n", inode->i_ino, rc); - RETURN(rc); + if (rc != -ENOENT) + CERROR("inode %lu: rc = %d\n", inode->i_ino, rc); + GOTO (failed, rc); } - *symname = lustre_msg_buf((*request)->rq_repmsg, 1); + body = lustre_msg_buf((*request)->rq_repmsg, REPLY_REC_OFF, + sizeof(*body)); + LASSERT(body != NULL); + LASSERT_REPSWABBED(*request, REPLY_REC_OFF); + + if ((body->valid & OBD_MD_LINKNAME) == 0) { + CERROR("OBD_MD_LINKNAME not set on reply\n"); + GOTO(failed, rc = -EPROTO); + } + + LASSERT(symlen != 0); + if (body->eadatasize != symlen) { + CERROR("inode %lu: symlink length %d not expected %d\n", + inode->i_ino, body->eadatasize - 1, symlen - 1); + GOTO(failed, rc = -EPROTO); + } + + *symname = lustre_msg_buf((*request)->rq_repmsg, REPLY_REC_OFF + 1, + symlen); + if (*symname == NULL || + strnlen (*symname, symlen) != symlen - 1) { + /* not full/NULL terminated */ + CERROR("inode %lu: symlink not NULL terminated string" + "of length %d\n", inode->i_ino, symlen - 1); + GOTO(failed, rc = -EPROTO); + } OBD_ALLOC(lli->lli_symlink_name, symlen); /* do not return an error if we cannot cache the symlink locally */ - if (lli->lli_symlink_name) + if (lli->lli_symlink_name) { memcpy(lli->lli_symlink_name, *symname, symlen); + ptlrpc_req_finished (*request); + *request = NULL; + *symname = lli->lli_symlink_name; + } RETURN(0); + + failed: + ptlrpc_req_finished (*request); + RETURN (rc); } static int ll_readlink(struct dentry *dentry, char *buffer, int buflen) @@ -69,60 +109,109 @@ static int ll_readlink(struct dentry *dentry, char *buffer, int buflen) int rc; ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op\n"); /* on symlinks lli_open_sem protects lli_symlink_name allocation/data */ - down(&lli->lli_open_sem); + down(&lli->lli_size_sem); rc = ll_readlink_internal(inode, &request, &symname); if (rc) GOTO(out, rc); rc = vfs_readlink(dentry, buffer, buflen, symname); - out: - up(&lli->lli_open_sem); ptlrpc_req_finished(request); - + out: + up(&lli->lli_size_sem); RETURN(rc); } -static int ll_follow_link(struct dentry *dentry, struct nameidata *nd, - struct lookup_intent *it) +#ifdef HAVE_COOKIE_FOLLOW_LINK +# define LL_FOLLOW_LINK_RETURN_TYPE void * +#else +# define LL_FOLLOW_LINK_RETURN_TYPE int +#endif + +static LL_FOLLOW_LINK_RETURN_TYPE ll_follow_link(struct dentry *dentry, + struct nameidata *nd) { struct inode *inode = dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); +#ifdef HAVE_VFS_INTENT_PATCHES + struct lookup_intent *it = ll_nd2it(nd); +#endif struct ptlrpc_request *request; - int op = 0, mode = 0, rc; + int rc; char *symname; ENTRY; +#ifdef HAVE_VFS_INTENT_PATCHES if (it != NULL) { - op = it->it_op; - mode = it->it_mode; + int op = it->it_op; + int mode = it->it_create_mode; - ll_intent_release(dentry, it); + ll_intent_release(it); + it->it_op = op; + it->it_create_mode = mode; } +#endif - down(&lli->lli_open_sem); + CDEBUG(D_VFSTRACE, "VFS Op\n"); + down(&lli->lli_size_sem); rc = ll_readlink_internal(inode, &request, &symname); - up(&lli->lli_open_sem); - if (rc) + up(&lli->lli_size_sem); + if (rc) { + path_release(nd); /* Kernel assumes that ->follow_link() + releases nameidata on error */ GOTO(out, rc); - - if (it != NULL) { - it->it_op = op; - it->it_mode = mode; } - rc = vfs_follow_link_it(nd, symname, it); - out: +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)) + rc = vfs_follow_link(nd, symname); +#else +#ifdef HAVE_COOKIE_FOLLOW_LINK + nd_set_link(nd, symname); + /* @symname may contain a pointer to the request message buffer, + we delay request releasing until ll_put_link then. */ + RETURN(request); +#else + if (request != NULL) { + /* falling back to recursive follow link if the request + * needs to be cleaned up still. */ + rc = vfs_follow_link(nd, symname); + GOTO(out, rc); + } + nd_set_link(nd, symname); + RETURN(0); +#endif +#endif +out: ptlrpc_req_finished(request); - +#ifdef HAVE_COOKIE_FOLLOW_LINK + RETURN(ERR_PTR(rc)); +#else RETURN(rc); +#endif +} + +#ifdef HAVE_COOKIE_FOLLOW_LINK +static void ll_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) +{ + ptlrpc_req_finished(cookie); } +#endif -extern int ll_inode_revalidate(struct dentry *dentry); -extern int ll_setattr(struct dentry *de, struct iattr *attr); struct inode_operations ll_fast_symlink_inode_operations = { - readlink: ll_readlink, - setattr: ll_setattr, - follow_link2: ll_follow_link, - revalidate: ll_inode_revalidate + .readlink = ll_readlink, + .setattr = ll_setattr, +#ifdef HAVE_VFS_INTENT_PATCHES + .setattr_raw = ll_setattr_raw, +#endif + .follow_link = ll_follow_link, +#ifdef HAVE_COOKIE_FOLLOW_LINK + .put_link = ll_put_link, +#endif + .getattr = ll_getattr, + .permission = ll_inode_permission, + .setxattr = ll_setxattr, + .getxattr = ll_getxattr, + .listxattr = ll_listxattr, + .removexattr = ll_removexattr, };