linux/drivers/staging/lustre/lustre/llite/symlink.c
<<
>>
Prefs
   1/*
   2 * GPL HEADER START
   3 *
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 only,
   8 * as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License version 2 for more details (a copy is included
  14 * in the LICENSE file that accompanied this code).
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * version 2 along with this program; If not, see
  18 * http://www.gnu.org/licenses/gpl-2.0.html
  19 *
  20 * GPL HEADER END
  21 */
  22/*
  23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  24 * Use is subject to license terms.
  25 *
  26 * Copyright (c) 2011, 2012, Intel Corporation.
  27 */
  28/*
  29 * This file is part of Lustre, http://www.lustre.org/
  30 * Lustre is a trademark of Sun Microsystems, Inc.
  31 */
  32
  33#include <linux/fs.h>
  34#include <linux/mm.h>
  35#include <linux/stat.h>
  36#define DEBUG_SUBSYSTEM S_LLITE
  37
  38#include "llite_internal.h"
  39
  40static int ll_readlink_internal(struct inode *inode,
  41                                struct ptlrpc_request **request, char **symname)
  42{
  43        struct ll_inode_info *lli = ll_i2info(inode);
  44        struct ll_sb_info *sbi = ll_i2sbi(inode);
  45        int rc, symlen = i_size_read(inode) + 1;
  46        struct mdt_body *body;
  47        struct md_op_data *op_data;
  48
  49        *request = NULL;
  50
  51        if (lli->lli_symlink_name) {
  52                int print_limit = min_t(int, PAGE_SIZE - 128, symlen);
  53
  54                *symname = lli->lli_symlink_name;
  55                /* If the total CDEBUG() size is larger than a page, it
  56                 * will print a warning to the console, avoid this by
  57                 * printing just the last part of the symlink.
  58                 */
  59                CDEBUG(D_INODE, "using cached symlink %s%.*s, len = %d\n",
  60                       print_limit < symlen ? "..." : "", print_limit,
  61                       (*symname) + symlen - print_limit, symlen);
  62                return 0;
  63        }
  64
  65        op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, symlen,
  66                                     LUSTRE_OPC_ANY, NULL);
  67        if (IS_ERR(op_data))
  68                return PTR_ERR(op_data);
  69
  70        op_data->op_valid = OBD_MD_LINKNAME;
  71        rc = md_getattr(sbi->ll_md_exp, op_data, request);
  72        ll_finish_md_op_data(op_data);
  73        if (rc) {
  74                if (rc != -ENOENT)
  75                        CERROR("%s: inode "DFID": rc = %d\n",
  76                               ll_get_fsname(inode->i_sb, NULL, 0),
  77                               PFID(ll_inode2fid(inode)), rc);
  78                goto failed;
  79        }
  80
  81        body = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_BODY);
  82        if ((body->mbo_valid & OBD_MD_LINKNAME) == 0) {
  83                CERROR("OBD_MD_LINKNAME not set on reply\n");
  84                rc = -EPROTO;
  85                goto failed;
  86        }
  87
  88        LASSERT(symlen != 0);
  89        if (body->mbo_eadatasize != symlen) {
  90                CERROR("%s: inode "DFID": symlink length %d not expected %d\n",
  91                       ll_get_fsname(inode->i_sb, NULL, 0),
  92                       PFID(ll_inode2fid(inode)), body->mbo_eadatasize - 1,
  93                       symlen - 1);
  94                rc = -EPROTO;
  95                goto failed;
  96        }
  97
  98        *symname = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_MD);
  99        if (!*symname ||
 100            strnlen(*symname, symlen) != symlen - 1) {
 101                /* not full/NULL terminated */
 102                CERROR("inode %lu: symlink not NULL terminated string of length %d\n",
 103                       inode->i_ino, symlen - 1);
 104                rc = -EPROTO;
 105                goto failed;
 106        }
 107
 108        lli->lli_symlink_name = kzalloc(symlen, GFP_NOFS);
 109        /* do not return an error if we cannot cache the symlink locally */
 110        if (lli->lli_symlink_name) {
 111                memcpy(lli->lli_symlink_name, *symname, symlen);
 112                *symname = lli->lli_symlink_name;
 113        }
 114        return 0;
 115
 116failed:
 117        return rc;
 118}
 119
 120static void ll_put_link(void *p)
 121{
 122        ptlrpc_req_finished(p);
 123}
 124
 125static const char *ll_get_link(struct dentry *dentry,
 126                               struct inode *inode,
 127                               struct delayed_call *done)
 128{
 129        struct ptlrpc_request *request = NULL;
 130        int rc;
 131        char *symname = NULL;
 132        if (!dentry)
 133                return ERR_PTR(-ECHILD);
 134
 135        CDEBUG(D_VFSTRACE, "VFS Op\n");
 136        ll_inode_size_lock(inode);
 137        rc = ll_readlink_internal(inode, &request, &symname);
 138        ll_inode_size_unlock(inode);
 139        if (rc) {
 140                ptlrpc_req_finished(request);
 141                return ERR_PTR(rc);
 142        }
 143
 144        /* symname may contain a pointer to the request message buffer,
 145         * we delay request releasing then.
 146         */
 147        set_delayed_call(done, ll_put_link, request);
 148        return symname;
 149}
 150
 151const struct inode_operations ll_fast_symlink_inode_operations = {
 152        .readlink       = generic_readlink,
 153        .setattr        = ll_setattr,
 154        .get_link       = ll_get_link,
 155        .getattr        = ll_getattr,
 156        .permission     = ll_inode_permission,
 157        .listxattr      = ll_listxattr,
 158};
 159