X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fsymlink.c;h=4b1a9daf50b8dac36433ded65bef08d099c90036;hp=365910fb6c38e58bfd1aae6b7045fea4f8679b3e;hb=ab8b977f77e44c3f4d57be2244e9df898fd15316;hpb=fbf5870b9848929d352460f1f005b79c0b5ccc5a diff --git a/lustre/llite/symlink.c b/lustre/llite/symlink.c index 365910f..4b1a9da 100644 --- a/lustre/llite/symlink.c +++ b/lustre/llite/symlink.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -26,8 +24,10 @@ * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011, 2014, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -37,11 +37,9 @@ #include #include #include -#include #include #define DEBUG_SUBSYSTEM S_LLITE -#include #include "llite_internal.h" static int ll_readlink_internal(struct inode *inode, @@ -51,38 +49,53 @@ static int ll_readlink_internal(struct inode *inode, struct ll_sb_info *sbi = ll_i2sbi(inode); int rc, symlen = i_size_read(inode) + 1; struct mdt_body *body; - struct obd_capa *oc; + struct md_op_data *op_data; ENTRY; *request = NULL; - if (lli->lli_symlink_name) { - *symname = lli->lli_symlink_name; - CDEBUG(D_INODE, "using cached symlink %s\n", *symname); - RETURN(0); - } - - 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 (lli->lli_symlink_name) { + int print_limit = min_t(int, PAGE_SIZE - 128, symlen); + + *symname = lli->lli_symlink_name; + /* If the total CDEBUG() size is larger than a page, it + * will print a warning to the console, avoid this by + * printing just the last part of the symlink. */ + CDEBUG(D_INODE, "using cached symlink %s%.*s, len = %d\n", + print_limit < symlen ? "..." : "", print_limit, + (*symname) + symlen - print_limit, symlen); + RETURN(0); + } + + op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, symlen, + LUSTRE_OPC_ANY, NULL); + if (IS_ERR(op_data)) + RETURN(PTR_ERR(op_data)); + + op_data->op_valid = OBD_MD_LINKNAME; + rc = md_getattr(sbi->ll_md_exp, op_data, request); + ll_finish_md_op_data(op_data); if (rc) { if (rc != -ENOENT) - CERROR("inode %lu: rc = %d\n", inode->i_ino, rc); + CERROR("%s: inode "DFID": rc = %d\n", + ll_get_fsname(inode->i_sb, NULL, 0), + PFID(ll_inode2fid(inode)), rc); GOTO (failed, rc); } body = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_BODY); LASSERT(body != NULL); - 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); + if ((body->mbo_valid & OBD_MD_LINKNAME) == 0) { + CERROR("OBD_MD_LINKNAME not set on reply\n"); + GOTO(failed, rc = -EPROTO); + } + + LASSERT(symlen != 0); + if (body->mbo_eadatasize != symlen) { + CERROR("%s: inode "DFID": symlink length %d not expected %d\n", + ll_get_fsname(inode->i_sb, NULL, 0), + PFID(ll_inode2fid(inode)), body->mbo_eadatasize - 1, + symlen - 1); GOTO(failed, rc = -EPROTO); } @@ -90,8 +103,9 @@ static int ll_readlink_internal(struct inode *inode, 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); + CERROR("%s: inode "DFID": symlink not NULL terminated string" + "of length %d\n", ll_get_fsname(inode->i_sb, NULL, 0), + PFID(ll_inode2fid(inode)), symlen - 1); GOTO(failed, rc = -EPROTO); } @@ -99,142 +113,92 @@ static int ll_readlink_internal(struct inode *inode, /* do not return an error if we cannot cache the symlink locally */ 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); +failed: RETURN (rc); } -static int ll_readlink(struct dentry *dentry, char *buffer, int buflen) +#ifdef HAVE_SYMLINK_OPS_USE_NAMEIDATA +static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct inode *inode = dentry->d_inode; - struct ptlrpc_request *request; - char *symname; - int rc; - ENTRY; - - CDEBUG(D_VFSTRACE, "VFS Op\n"); - /* on symlinks lli_open_sem protects lli_symlink_name allocation/data */ - ll_inode_size_lock(inode, 0); - rc = ll_readlink_internal(inode, &request, &symname); - if (rc) - GOTO(out, rc); - - rc = vfs_readlink(dentry, buffer, buflen, symname); - ptlrpc_req_finished(request); - out: - ll_inode_size_unlock(inode, 0); - RETURN(rc); -} - -#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; -#ifdef HAVE_VFS_INTENT_PATCHES - struct lookup_intent *it = ll_nd2it(nd); -#endif - struct ptlrpc_request *request; - int rc; - char *symname; - ENTRY; - -#ifdef HAVE_VFS_INTENT_PATCHES - if (it != NULL) { - int op = it->it_op; - int mode = it->it_create_mode; - - ll_intent_release(it); - it->it_op = op; - it->it_create_mode = mode; - } -#endif + struct inode *inode = dentry->d_inode; + struct ptlrpc_request *request = NULL; + int rc; + char *symname = NULL; + ENTRY; CDEBUG(D_VFSTRACE, "VFS Op\n"); -#if THREAD_SIZE < 8192 - /* - * We set the limits recursive symlink to 5 - * instead of default 8 when kernel has 4k stack - * to prevent stack overflow. - */ - if (current->link_count >= 5) { + /* Limit the recursive symlink depth to 5 instead of default + * 8 links when kernel has 4k stack to prevent stack overflow. + * For 8k stacks we need to limit it to 7 for local servers. */ + if (THREAD_SIZE < 8192 && current->link_count >= 6) { rc = -ELOOP; - GOTO(out_release, rc); - } -#endif - ll_inode_size_lock(inode, 0); - rc = ll_readlink_internal(inode, &request, &symname); - ll_inode_size_unlock(inode, 0); - if (rc) { -#if THREAD_SIZE < 8192 -out_release: -#endif - path_release(nd); /* Kernel assumes that ->follow_link() - releases nameidata on error */ - GOTO(out, rc); - } - -#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); + } else if (THREAD_SIZE == 8192 && current->link_count >= 8) { + rc = -ELOOP; + } else { + ll_inode_size_lock(inode); + rc = ll_readlink_internal(inode, &request, &symname); + ll_inode_size_unlock(inode); } - nd_set_link(nd, symname); - RETURN(0); -#endif -#endif -out: - ptlrpc_req_finished(request); -#ifdef HAVE_COOKIE_FOLLOW_LINK - RETURN(ERR_PTR(rc)); + if (rc) { + ptlrpc_req_finished(request); + request = NULL; + symname = ERR_PTR(rc); + } + + 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 - RETURN(rc); -#endif +static const char *ll_follow_link(struct dentry *dentry, void **cookie) +{ + struct inode *inode = d_inode(dentry); + struct ptlrpc_request *request; + char *symname; + int rc; + ENTRY; + + CDEBUG(D_VFSTRACE, "VFS Op\n"); + ll_inode_size_lock(inode); + rc = ll_readlink_internal(inode, &request, &symname); + ll_inode_size_unlock(inode); + if (rc < 0) { + ptlrpc_req_finished(request); + return ERR_PTR(rc); + } + + /* symname may contain a pointer to the request message buffer, + * we delay request releasing until ll_put_link then. + */ + *cookie = request; + RETURN(symname); } +#endif /* HAVE_SYMLINK_OPS_USE_NAMEIDATA */ -#ifdef HAVE_COOKIE_FOLLOW_LINK +#ifdef HAVE_SYMLINK_OPS_USE_NAMEIDATA static void ll_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) +#else +static void ll_put_link(struct inode *unused, void *cookie) +#endif { - ptlrpc_req_finished(cookie); + ptlrpc_req_finished(cookie); } -#endif struct inode_operations ll_fast_symlink_inode_operations = { - .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, + .readlink = generic_readlink, + .setattr = ll_setattr, + .follow_link = ll_follow_link, + .put_link = ll_put_link, + .getattr = ll_getattr, + .permission = ll_inode_permission, + .setxattr = ll_setxattr, + .getxattr = ll_getxattr, + .listxattr = ll_listxattr, + .removexattr = ll_removexattr, };