X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Fsymlink.c;h=e401266ed261345ea841f4b6ac03f32759fed7ec;hb=471854590f94f6c214b78e3d4bd4e2076667379f;hp=1b307d67b0f26845c547aa7aec01ba21920967a7;hpb=94c2ba8fc1b4f13c29231f84d18ac3b7ade2d5ed;p=fs%2Flustre-release.git diff --git a/lustre/llite/symlink.c b/lustre/llite/symlink.c index 1b307d6..e401266 100644 --- a/lustre/llite/symlink.c +++ b/lustre/llite/symlink.c @@ -1,62 +1,160 @@ -/* - * 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 + * Copyright (c) 2002 Cluster File Systems, Inc. * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) + * This file is part of Lustre, http://www.lustre.org. * - * Copyright (C) 1991, 1992 Linus Torvalds + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. * - * ext2 symlink handling code + * Lustre 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 for more details. * - * Modified for OBDFS: - * Copyright (C) 1999 Seagate Technology Inc. (author: braam@stelias.com) + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include -#include - +#include +#include #define DEBUG_SUBSYSTEM S_LLITE -#include /* for ENTRY and EXIT only */ #include +#include "llite_internal.h" -static int ll_readlink(struct dentry *dentry, char *buffer, int buflen) +static int ll_readlink_internal(struct inode *inode, + struct ptlrpc_request **request, char **symname) { - struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode); - struct ptlrpc_request *request; - char *tmp; - int rc, size; + struct ll_inode_info *lli = ll_i2info(inode); + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct ll_fid fid; + struct mds_body *body; + int rc, symlen = inode->i_size + 1; ENTRY; - rc = mdc_getattr(&sbi->ll_mdc_conn, - dentry->d_inode->i_ino, S_IFLNK, - OBD_MD_LINKNAME, dentry->d_inode->i_size, &request); + *request = NULL; + + if (lli->lli_symlink_name) { + *symname = lli->lli_symlink_name; + CDEBUG(D_INODE, "using cached symlink %s\n", *symname); + RETURN(0); + } + + ll_inode2fid(&fid, inode); + rc = mdc_getattr(sbi->ll_mdc_exp, &fid, + OBD_MD_LINKNAME, symlen, request); if (rc) { - CERROR("failure %d inode %ld\n", rc, - (long)dentry->d_inode->i_ino); - ptlrpc_free_req(request); + CERROR("inode %lu: rc = %d\n", inode->i_ino, rc); RETURN(rc); } - tmp = lustre_msg_buf(request->rq_repmsg, 1); - size = MIN(request->rq_repmsg->buflens[1], buflen); - rc = copy_to_user(buffer, tmp, size); - if (rc == 0) - rc = size; + body = lustre_msg_buf ((*request)->rq_repmsg, 0, sizeof (*body)); + LASSERT (body != NULL); + LASSERT_REPSWABBED (*request, 0); + + 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, 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) + memcpy(lli->lli_symlink_name, *symname, symlen); + + RETURN(0); + + failed: + ptlrpc_req_finished (*request); + RETURN (-EPROTO); +} + +static int ll_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + 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_open_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_open_sem); + RETURN(rc); +} + +static int ll_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode = dentry->d_inode; + struct ll_inode_info *lli = ll_i2info(inode); + struct lookup_intent *it = ll_nd2it(nd); + struct ptlrpc_request *request; + int rc; + char *symname; + ENTRY; + + 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; + } + + CDEBUG(D_VFSTRACE, "VFS Op\n"); + down(&lli->lli_open_sem); + rc = ll_readlink_internal(inode, &request, &symname); + up(&lli->lli_open_sem); + if (rc) + GOTO(out, rc); - ptlrpc_free_req(request); + rc = vfs_follow_link(nd, symname); + ptlrpc_req_finished(request); + out: RETURN(rc); } -extern int ll_setattr(struct dentry *de, struct iattr *attr); struct inode_operations ll_fast_symlink_inode_operations = { - readlink: ll_readlink, - setattr: ll_setattr + .readlink = ll_readlink, + .setattr = ll_setattr, + .setattr_raw = ll_setattr_raw, + .follow_link = ll_follow_link, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + .revalidate_it = ll_inode_revalidate_it +#else + .getattr_it = ll_getattr +#endif };