linux/drivers/staging/lustre/lustre/llite/llite_nfs.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) 2003, 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 * lustre/lustre/llite/llite_nfs.c
  33 *
  34 * NFS export of Lustre Light File System
  35 *
  36 * Author: Yury Umanets <umka@clusterfs.com>
  37 * Author: Huang Hua <huanghua@clusterfs.com>
  38 */
  39
  40#define DEBUG_SUBSYSTEM S_LLITE
  41#include "llite_internal.h"
  42#include <linux/exportfs.h>
  43
  44__u32 get_uuid2int(const char *name, int len)
  45{
  46        __u32 key0 = 0x12a3fe2d, key1 = 0x37abe8f9;
  47
  48        while (len--) {
  49                __u32 key = key1 + (key0 ^ (*name++ * 7152373));
  50
  51                if (key & 0x80000000)
  52                        key -= 0x7fffffff;
  53                key1 = key0;
  54                key0 = key;
  55        }
  56        return (key0 << 1);
  57}
  58
  59void get_uuid2fsid(const char *name, int len, __kernel_fsid_t *fsid)
  60{
  61        __u64 key = 0, key0 = 0x12a3fe2d, key1 = 0x37abe8f9;
  62
  63        while (len--) {
  64                key = key1 + (key0 ^ (*name++ * 7152373));
  65                if (key & 0x8000000000000000ULL)
  66                        key -= 0x7fffffffffffffffULL;
  67                key1 = key0;
  68                key0 = key;
  69        }
  70
  71        fsid->val[0] = key;
  72        fsid->val[1] = key >> 32;
  73}
  74
  75struct inode *search_inode_for_lustre(struct super_block *sb,
  76                                      const struct lu_fid *fid)
  77{
  78        struct ll_sb_info     *sbi = ll_s2sbi(sb);
  79        struct ptlrpc_request *req = NULL;
  80        struct inode      *inode = NULL;
  81        int                eadatalen = 0;
  82        unsigned long         hash = cl_fid_build_ino(fid,
  83                                                      ll_need_32bit_api(sbi));
  84        struct  md_op_data    *op_data;
  85        int                rc;
  86
  87        CDEBUG(D_INFO, "searching inode for:(%lu,"DFID")\n", hash, PFID(fid));
  88
  89        inode = ilookup5(sb, hash, ll_test_inode_by_fid, (void *)fid);
  90        if (inode)
  91                return inode;
  92
  93        rc = ll_get_default_mdsize(sbi, &eadatalen);
  94        if (rc)
  95                return ERR_PTR(rc);
  96
  97        /* Because inode is NULL, ll_prep_md_op_data can not
  98         * be used here. So we allocate op_data ourselves
  99         */
 100        op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
 101        if (!op_data)
 102                return ERR_PTR(-ENOMEM);
 103
 104        op_data->op_fid1 = *fid;
 105        op_data->op_mode = eadatalen;
 106        op_data->op_valid = OBD_MD_FLEASIZE;
 107
 108        /* mds_fid2dentry ignores f_type */
 109        rc = md_getattr(sbi->ll_md_exp, op_data, &req);
 110        kfree(op_data);
 111        if (rc) {
 112                CDEBUG(D_INFO, "can't get object attrs, fid "DFID", rc %d\n",
 113                       PFID(fid), rc);
 114                return ERR_PTR(rc);
 115        }
 116        rc = ll_prep_inode(&inode, req, sb, NULL);
 117        ptlrpc_req_finished(req);
 118        if (rc)
 119                return ERR_PTR(rc);
 120
 121        return inode;
 122}
 123
 124struct lustre_nfs_fid {
 125        struct lu_fid   lnf_child;
 126        struct lu_fid   lnf_parent;
 127};
 128
 129static struct dentry *
 130ll_iget_for_nfs(struct super_block *sb, struct lu_fid *fid, struct lu_fid *parent)
 131{
 132        struct inode  *inode;
 133        struct dentry *result;
 134
 135        if (!fid_is_sane(fid))
 136                return ERR_PTR(-ESTALE);
 137
 138        CDEBUG(D_INFO, "Get dentry for fid: " DFID "\n", PFID(fid));
 139
 140        inode = search_inode_for_lustre(sb, fid);
 141        if (IS_ERR(inode))
 142                return ERR_CAST(inode);
 143
 144        if (is_bad_inode(inode)) {
 145                /* we didn't find the right inode.. */
 146                iput(inode);
 147                return ERR_PTR(-ESTALE);
 148        }
 149
 150        result = d_obtain_alias(inode);
 151        if (IS_ERR(result)) {
 152                iput(inode);
 153                return result;
 154        }
 155
 156        /**
 157         * In case d_obtain_alias() found a disconnected dentry, always update
 158         * lli_pfid to allow later operation (normally open) have parent fid,
 159         * which may be used by MDS to create data.
 160         */
 161        if (parent) {
 162                struct ll_inode_info *lli = ll_i2info(inode);
 163
 164                spin_lock(&lli->lli_lock);
 165                lli->lli_pfid = *parent;
 166                spin_unlock(&lli->lli_lock);
 167        }
 168
 169        /* N.B. d_obtain_alias() drops inode ref on error */
 170        result = d_obtain_alias(inode);
 171        if (!IS_ERR(result)) {
 172                int rc;
 173
 174                rc = ll_d_init(result);
 175                if (rc < 0) {
 176                        dput(result);
 177                        result = ERR_PTR(rc);
 178                } else {
 179                        struct ll_dentry_data *ldd = ll_d2d(result);
 180
 181                        /*
 182                         * Need to signal to the ll_intent_file_open that
 183                         * we came from NFS and so opencache needs to be
 184                         * enabled for this one
 185                         */
 186                        ldd->lld_nfs_dentry = 1;
 187                }
 188        }
 189
 190        return result;
 191}
 192
 193/**
 194 * \a connectable - is nfsd will connect himself or this should be done
 195 *                at lustre
 196 *
 197 * The return value is file handle type:
 198 * 1 -- contains child file handle;
 199 * 2 -- contains child file handle and parent file handle;
 200 * 255 -- error.
 201 */
 202static int ll_encode_fh(struct inode *inode, __u32 *fh, int *plen,
 203                        struct inode *parent)
 204{
 205        int fileid_len = sizeof(struct lustre_nfs_fid) / 4;
 206        struct lustre_nfs_fid *nfs_fid = (void *)fh;
 207
 208        CDEBUG(D_INFO, "%s: encoding for ("DFID") maxlen=%d minlen=%d\n",
 209               ll_get_fsname(inode->i_sb, NULL, 0),
 210               PFID(ll_inode2fid(inode)), *plen, fileid_len);
 211
 212        if (*plen < fileid_len) {
 213                *plen = fileid_len;
 214                return FILEID_INVALID;
 215        }
 216
 217        nfs_fid->lnf_child = *ll_inode2fid(inode);
 218        if (parent)
 219                nfs_fid->lnf_parent = *ll_inode2fid(parent);
 220        else
 221                fid_zero(&nfs_fid->lnf_parent);
 222        *plen = fileid_len;
 223
 224        return FILEID_LUSTRE;
 225}
 226
 227static int ll_nfs_get_name_filldir(struct dir_context *ctx, const char *name,
 228                                   int namelen, loff_t hash, u64 ino,
 229                                   unsigned type)
 230{
 231        /* It is hack to access lde_fid for comparison with lgd_fid.
 232         * So the input 'name' must be part of the 'lu_dirent'.
 233         */
 234        struct lu_dirent *lde = container_of0(name, struct lu_dirent, lde_name);
 235        struct ll_getname_data *lgd =
 236                container_of(ctx, struct ll_getname_data, ctx);
 237        struct lu_fid fid;
 238
 239        fid_le_to_cpu(&fid, &lde->lde_fid);
 240        if (lu_fid_eq(&fid, &lgd->lgd_fid)) {
 241                memcpy(lgd->lgd_name, name, namelen);
 242                lgd->lgd_name[namelen] = 0;
 243                lgd->lgd_found = 1;
 244        }
 245        return lgd->lgd_found;
 246}
 247
 248static int ll_get_name(struct dentry *dentry, char *name,
 249                       struct dentry *child)
 250{
 251        struct inode *dir = d_inode(dentry);
 252        int rc;
 253        struct ll_getname_data lgd = {
 254                .lgd_name = name,
 255                .lgd_fid = ll_i2info(d_inode(child))->lli_fid,
 256                .ctx.actor = ll_nfs_get_name_filldir,
 257        };
 258        struct md_op_data *op_data;
 259        __u64 pos = 0;
 260
 261        if (!dir || !S_ISDIR(dir->i_mode)) {
 262                rc = -ENOTDIR;
 263                goto out;
 264        }
 265
 266        if (!dir->i_fop) {
 267                rc = -EINVAL;
 268                goto out;
 269        }
 270
 271        op_data = ll_prep_md_op_data(NULL, dir, dir, NULL, 0, 0,
 272                                     LUSTRE_OPC_ANY, dir);
 273        if (IS_ERR(op_data)) {
 274                rc = PTR_ERR(op_data);
 275                goto out;
 276        }
 277
 278        op_data->op_max_pages = ll_i2sbi(dir)->ll_md_brw_pages;
 279        inode_lock(dir);
 280        rc = ll_dir_read(dir, &pos, op_data, &lgd.ctx);
 281        inode_unlock(dir);
 282        ll_finish_md_op_data(op_data);
 283        if (!rc && !lgd.lgd_found)
 284                rc = -ENOENT;
 285out:
 286        return rc;
 287}
 288
 289static struct dentry *ll_fh_to_dentry(struct super_block *sb, struct fid *fid,
 290                                      int fh_len, int fh_type)
 291{
 292        struct lustre_nfs_fid *nfs_fid = (struct lustre_nfs_fid *)fid;
 293
 294        if (fh_type != FILEID_LUSTRE)
 295                return ERR_PTR(-EPROTO);
 296
 297        return ll_iget_for_nfs(sb, &nfs_fid->lnf_child, &nfs_fid->lnf_parent);
 298}
 299
 300static struct dentry *ll_fh_to_parent(struct super_block *sb, struct fid *fid,
 301                                      int fh_len, int fh_type)
 302{
 303        struct lustre_nfs_fid *nfs_fid = (struct lustre_nfs_fid *)fid;
 304
 305        if (fh_type != FILEID_LUSTRE)
 306                return ERR_PTR(-EPROTO);
 307
 308        return ll_iget_for_nfs(sb, &nfs_fid->lnf_parent, NULL);
 309}
 310
 311int ll_dir_get_parent_fid(struct inode *dir, struct lu_fid *parent_fid)
 312{
 313        struct ptlrpc_request *req = NULL;
 314        struct ll_sb_info     *sbi;
 315        struct mdt_body       *body;
 316        static const char dotdot[] = "..";
 317        struct md_op_data     *op_data;
 318        int                rc;
 319        int                   lmmsize;
 320
 321        LASSERT(dir && S_ISDIR(dir->i_mode));
 322
 323        sbi = ll_s2sbi(dir->i_sb);
 324
 325        CDEBUG(D_INFO, "%s: getting parent for ("DFID")\n",
 326               ll_get_fsname(dir->i_sb, NULL, 0),
 327               PFID(ll_inode2fid(dir)));
 328
 329        rc = ll_get_default_mdsize(sbi, &lmmsize);
 330        if (rc != 0)
 331                return rc;
 332
 333        op_data = ll_prep_md_op_data(NULL, dir, NULL, dotdot,
 334                                     strlen(dotdot), lmmsize,
 335                                     LUSTRE_OPC_ANY, NULL);
 336        if (IS_ERR(op_data))
 337                return PTR_ERR(op_data);
 338
 339        rc = md_getattr_name(sbi->ll_md_exp, op_data, &req);
 340        ll_finish_md_op_data(op_data);
 341        if (rc) {
 342                CERROR("%s: failure inode "DFID" get parent: rc = %d\n",
 343                       ll_get_fsname(dir->i_sb, NULL, 0),
 344                       PFID(ll_inode2fid(dir)), rc);
 345                return rc;
 346        }
 347        body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
 348        /*
 349         * LU-3952: MDT may lost the FID of its parent, we should not crash
 350         * the NFS server, ll_iget_for_nfs() will handle the error.
 351         */
 352        if (body->mbo_valid & OBD_MD_FLID) {
 353                CDEBUG(D_INFO, "parent for " DFID " is " DFID "\n",
 354                       PFID(ll_inode2fid(dir)), PFID(&body->mbo_fid1));
 355                *parent_fid = body->mbo_fid1;
 356        }
 357
 358        ptlrpc_req_finished(req);
 359        return 0;
 360}
 361
 362static struct dentry *ll_get_parent(struct dentry *dchild)
 363{
 364        struct lu_fid parent_fid = { 0 };
 365        struct dentry *dentry;
 366        int rc;
 367
 368        rc = ll_dir_get_parent_fid(dchild->d_inode, &parent_fid);
 369        if (rc)
 370                return ERR_PTR(rc);
 371
 372        dentry = ll_iget_for_nfs(dchild->d_inode->i_sb, &parent_fid, NULL);
 373
 374        return dentry;
 375}
 376
 377const struct export_operations lustre_export_operations = {
 378        .get_parent = ll_get_parent,
 379        .encode_fh  = ll_encode_fh,
 380        .get_name   = ll_get_name,
 381        .fh_to_dentry = ll_fh_to_dentry,
 382        .fh_to_parent = ll_fh_to_parent,
 383};
 384