X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Fsymlink.c;h=5b2fe077ecfe4abfe1267f96eca039d98d3caf7e;hb=665e36b780faa2144cecccd29a0d8a8196a76903;hp=83c41f448c975c3aafe88d982f943b1a29e73fb7;hpb=00102f342959b094f035b618c0b7acf477de35b4;p=fs%2Flustre-release.git diff --git a/lustre/llite/symlink.c b/lustre/llite/symlink.c index 83c41f4..5b2fe07 100644 --- a/lustre/llite/symlink.c +++ b/lustre/llite/symlink.c @@ -1,52 +1,228 @@ -/* - * linux/fs/ext2/symlink.c +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: * - * This code is issued under the GNU General Public License. - * See the file COPYING in this distribution + * GPL HEADER START * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * from + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. * - * linux/fs/minix/symlink.c + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). * - * Copyright (C) 1991, 1992 Linus Torvalds + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * ext2 symlink handling code + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. * - * Modified for OBDFS: - * Copyright (C) 1999 Seagate Technology Inc. (author: braam@stelias.com) + * GPL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. */ #include #include #include -#include +#include +#include +#define DEBUG_SUBSYSTEM S_LLITE + +#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 = i_size_read(inode) + 1; + struct mdt_body *body; + struct obd_capa *oc; + 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 (rc) { + if (rc != -ENOENT) + CERROR("inode %lu: rc = %d\n", inode->i_ino, 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); + GOTO(failed, rc = -EPROTO); + } + + *symname = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_MD); + 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); + } -#define DEBUG_SUBSYSTEM S_LLIGHT + OBD_ALLOC(lli->lli_symlink_name, symlen); + /* 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; + } -#include /* for ENTRY and EXIT only */ -#include + RETURN(0); -static int ll_fast_readlink(struct dentry *dentry, char *buffer, int buflen) + failed: + ptlrpc_req_finished (*request); + RETURN (rc); +} + +static int ll_readlink(struct dentry *dentry, char *buffer, int buflen) { - char *s = ll_i2info(dentry->d_inode)->lli_inline; - return vfs_readlink(dentry, buffer, buflen, s); + struct inode *inode = dentry->d_inode; + struct ll_inode_info *lli = ll_i2info(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 */ + down(&lli->lli_size_sem); + rc = ll_readlink_internal(inode, &request, &symname); + if (rc) + GOTO(out, rc); + + rc = vfs_readlink(dentry, buffer, buflen, symname); + ptlrpc_req_finished(request); + out: + up(&lli->lli_size_sem); + RETURN(rc); } -static int ll_fast_follow_link(struct dentry *dentry, struct nameidata *nd) +#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) { - char *s = ll_i2info(dentry->d_inode)->lli_inline; - return vfs_follow_link(nd, s); + 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 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 + + CDEBUG(D_VFSTRACE, "VFS Op\n"); + down(&lli->lli_size_sem); + rc = ll_readlink_internal(inode, &request, &symname); + up(&lli->lli_size_sem); + if (rc) { + 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); + } + 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_setattr(struct dentry *de, struct iattr *attr); struct inode_operations ll_fast_symlink_inode_operations = { - readlink: ll_fast_readlink, - follow_link: ll_fast_follow_link, - setattr: ll_setattr + .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, }; -