linux/fs/nfs/mount_clnt.c
<<
>>
Prefs
   1/*
   2 * In-kernel MOUNT protocol client
   3 *
   4 * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
   5 */
   6
   7#include <linux/types.h>
   8#include <linux/socket.h>
   9#include <linux/kernel.h>
  10#include <linux/errno.h>
  11#include <linux/uio.h>
  12#include <linux/net.h>
  13#include <linux/in.h>
  14#include <linux/sunrpc/clnt.h>
  15#include <linux/sunrpc/sched.h>
  16#include <linux/nfs_fs.h>
  17#include "internal.h"
  18
  19#ifdef NFS_DEBUG
  20# define NFSDBG_FACILITY        NFSDBG_MOUNT
  21#endif
  22
  23/*
  24 * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4
  25 */
  26#define MNTPATHLEN              (1024)
  27
  28/*
  29 * XDR data type sizes
  30 */
  31#define encode_dirpath_sz       (1 + XDR_QUADLEN(MNTPATHLEN))
  32#define MNT_status_sz           (1)
  33#define MNT_fhs_status_sz       (1)
  34#define MNT_fhandle_sz          XDR_QUADLEN(NFS2_FHSIZE)
  35#define MNT_fhandle3_sz         (1 + XDR_QUADLEN(NFS3_FHSIZE))
  36#define MNT_authflav3_sz        (1 + NFS_MAX_SECFLAVORS)
  37
  38/*
  39 * XDR argument and result sizes
  40 */
  41#define MNT_enc_dirpath_sz      encode_dirpath_sz
  42#define MNT_dec_mountres_sz     (MNT_status_sz + MNT_fhandle_sz)
  43#define MNT_dec_mountres3_sz    (MNT_status_sz + MNT_fhandle_sz + \
  44                                 MNT_authflav3_sz)
  45
  46/*
  47 * Defined by RFC 1094, section A.5
  48 */
  49enum {
  50        MOUNTPROC_NULL          = 0,
  51        MOUNTPROC_MNT           = 1,
  52        MOUNTPROC_DUMP          = 2,
  53        MOUNTPROC_UMNT          = 3,
  54        MOUNTPROC_UMNTALL       = 4,
  55        MOUNTPROC_EXPORT        = 5,
  56};
  57
  58/*
  59 * Defined by RFC 1813, section 5.2
  60 */
  61enum {
  62        MOUNTPROC3_NULL         = 0,
  63        MOUNTPROC3_MNT          = 1,
  64        MOUNTPROC3_DUMP         = 2,
  65        MOUNTPROC3_UMNT         = 3,
  66        MOUNTPROC3_UMNTALL      = 4,
  67        MOUNTPROC3_EXPORT       = 5,
  68};
  69
  70static const struct rpc_program mnt_program;
  71
  72/*
  73 * Defined by OpenGroup XNFS Version 3W, chapter 8
  74 */
  75enum mountstat {
  76        MNT_OK                  = 0,
  77        MNT_EPERM               = 1,
  78        MNT_ENOENT              = 2,
  79        MNT_EACCES              = 13,
  80        MNT_EINVAL              = 22,
  81};
  82
  83static struct {
  84        u32 status;
  85        int errno;
  86} mnt_errtbl[] = {
  87        { .status = MNT_OK,                     .errno = 0,             },
  88        { .status = MNT_EPERM,                  .errno = -EPERM,        },
  89        { .status = MNT_ENOENT,                 .errno = -ENOENT,       },
  90        { .status = MNT_EACCES,                 .errno = -EACCES,       },
  91        { .status = MNT_EINVAL,                 .errno = -EINVAL,       },
  92};
  93
  94/*
  95 * Defined by RFC 1813, section 5.1.5
  96 */
  97enum mountstat3 {
  98        MNT3_OK                 = 0,            /* no error */
  99        MNT3ERR_PERM            = 1,            /* Not owner */
 100        MNT3ERR_NOENT           = 2,            /* No such file or directory */
 101        MNT3ERR_IO              = 5,            /* I/O error */
 102        MNT3ERR_ACCES           = 13,           /* Permission denied */
 103        MNT3ERR_NOTDIR          = 20,           /* Not a directory */
 104        MNT3ERR_INVAL           = 22,           /* Invalid argument */
 105        MNT3ERR_NAMETOOLONG     = 63,           /* Filename too long */
 106        MNT3ERR_NOTSUPP         = 10004,        /* Operation not supported */
 107        MNT3ERR_SERVERFAULT     = 10006,        /* A failure on the server */
 108};
 109
 110static struct {
 111        u32 status;
 112        int errno;
 113} mnt3_errtbl[] = {
 114        { .status = MNT3_OK,                    .errno = 0,             },
 115        { .status = MNT3ERR_PERM,               .errno = -EPERM,        },
 116        { .status = MNT3ERR_NOENT,              .errno = -ENOENT,       },
 117        { .status = MNT3ERR_IO,                 .errno = -EIO,          },
 118        { .status = MNT3ERR_ACCES,              .errno = -EACCES,       },
 119        { .status = MNT3ERR_NOTDIR,             .errno = -ENOTDIR,      },
 120        { .status = MNT3ERR_INVAL,              .errno = -EINVAL,       },
 121        { .status = MNT3ERR_NAMETOOLONG,        .errno = -ENAMETOOLONG, },
 122        { .status = MNT3ERR_NOTSUPP,            .errno = -ENOTSUPP,     },
 123        { .status = MNT3ERR_SERVERFAULT,        .errno = -EREMOTEIO,    },
 124};
 125
 126struct mountres {
 127        int errno;
 128        struct nfs_fh *fh;
 129        unsigned int *auth_count;
 130        rpc_authflavor_t *auth_flavors;
 131};
 132
 133struct mnt_fhstatus {
 134        u32 status;
 135        struct nfs_fh *fh;
 136};
 137
 138/**
 139 * nfs_mount - Obtain an NFS file handle for the given host and path
 140 * @info: pointer to mount request arguments
 141 *
 142 * Uses default timeout parameters specified by underlying transport.
 143 */
 144int nfs_mount(struct nfs_mount_request *info)
 145{
 146        struct mountres result = {
 147                .fh             = info->fh,
 148                .auth_count     = info->auth_flav_len,
 149                .auth_flavors   = info->auth_flavs,
 150        };
 151        struct rpc_message msg  = {
 152                .rpc_argp       = info->dirpath,
 153                .rpc_resp       = &result,
 154        };
 155        struct rpc_create_args args = {
 156                .net            = info->net,
 157                .protocol       = info->protocol,
 158                .address        = info->sap,
 159                .addrsize       = info->salen,
 160                .servername     = info->hostname,
 161                .program        = &mnt_program,
 162                .version        = info->version,
 163                .authflavor     = RPC_AUTH_UNIX,
 164        };
 165        struct rpc_clnt         *mnt_clnt;
 166        int                     status;
 167
 168        dprintk("NFS: sending MNT request for %s:%s\n",
 169                (info->hostname ? info->hostname : "server"),
 170                        info->dirpath);
 171
 172        if (info->noresvport)
 173                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 174
 175        mnt_clnt = rpc_create(&args);
 176        if (IS_ERR(mnt_clnt))
 177                goto out_clnt_err;
 178
 179        if (info->version == NFS_MNT3_VERSION)
 180                msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
 181        else
 182                msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
 183
 184        status = rpc_call_sync(mnt_clnt, &msg, 0);
 185        rpc_shutdown_client(mnt_clnt);
 186
 187        if (status < 0)
 188                goto out_call_err;
 189        if (result.errno != 0)
 190                goto out_mnt_err;
 191
 192        dprintk("NFS: MNT request succeeded\n");
 193        status = 0;
 194
 195out:
 196        return status;
 197
 198out_clnt_err:
 199        status = PTR_ERR(mnt_clnt);
 200        dprintk("NFS: failed to create MNT RPC client, status=%d\n", status);
 201        goto out;
 202
 203out_call_err:
 204        dprintk("NFS: MNT request failed, status=%d\n", status);
 205        goto out;
 206
 207out_mnt_err:
 208        dprintk("NFS: MNT server returned result %d\n", result.errno);
 209        status = result.errno;
 210        goto out;
 211}
 212
 213/**
 214 * nfs_umount - Notify a server that we have unmounted this export
 215 * @info: pointer to umount request arguments
 216 *
 217 * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
 218 * use UDP.
 219 */
 220void nfs_umount(const struct nfs_mount_request *info)
 221{
 222        static const struct rpc_timeout nfs_umnt_timeout = {
 223                .to_initval = 1 * HZ,
 224                .to_maxval = 3 * HZ,
 225                .to_retries = 2,
 226        };
 227        struct rpc_create_args args = {
 228                .net            = info->net,
 229                .protocol       = IPPROTO_UDP,
 230                .address        = info->sap,
 231                .addrsize       = info->salen,
 232                .timeout        = &nfs_umnt_timeout,
 233                .servername     = info->hostname,
 234                .program        = &mnt_program,
 235                .version        = info->version,
 236                .authflavor     = RPC_AUTH_UNIX,
 237                .flags          = RPC_CLNT_CREATE_NOPING,
 238        };
 239        struct rpc_message msg  = {
 240                .rpc_argp       = info->dirpath,
 241        };
 242        struct rpc_clnt *clnt;
 243        int status;
 244
 245        if (info->noresvport)
 246                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 247
 248        clnt = rpc_create(&args);
 249        if (IS_ERR(clnt))
 250                goto out_clnt_err;
 251
 252        dprintk("NFS: sending UMNT request for %s:%s\n",
 253                (info->hostname ? info->hostname : "server"), info->dirpath);
 254
 255        if (info->version == NFS_MNT3_VERSION)
 256                msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT];
 257        else
 258                msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT];
 259
 260        status = rpc_call_sync(clnt, &msg, 0);
 261        rpc_shutdown_client(clnt);
 262
 263        if (unlikely(status < 0))
 264                goto out_call_err;
 265
 266        return;
 267
 268out_clnt_err:
 269        dprintk("NFS: failed to create UMNT RPC client, status=%ld\n",
 270                        PTR_ERR(clnt));
 271        return;
 272
 273out_call_err:
 274        dprintk("NFS: UMNT request failed, status=%d\n", status);
 275}
 276
 277/*
 278 * XDR encode/decode functions for MOUNT
 279 */
 280
 281static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
 282{
 283        const u32 pathname_len = strlen(pathname);
 284        __be32 *p;
 285
 286        BUG_ON(pathname_len > MNTPATHLEN);
 287        p = xdr_reserve_space(xdr, 4 + pathname_len);
 288        xdr_encode_opaque(p, pathname, pathname_len);
 289}
 290
 291static void mnt_xdr_enc_dirpath(struct rpc_rqst *req, struct xdr_stream *xdr,
 292                                const char *dirpath)
 293{
 294        encode_mntdirpath(xdr, dirpath);
 295}
 296
 297/*
 298 * RFC 1094: "A non-zero status indicates some sort of error.  In this
 299 * case, the status is a UNIX error number."  This can be problematic
 300 * if the server and client use different errno values for the same
 301 * error.
 302 *
 303 * However, the OpenGroup XNFS spec provides a simple mapping that is
 304 * independent of local errno values on the server and the client.
 305 */
 306static int decode_status(struct xdr_stream *xdr, struct mountres *res)
 307{
 308        unsigned int i;
 309        u32 status;
 310        __be32 *p;
 311
 312        p = xdr_inline_decode(xdr, 4);
 313        if (unlikely(p == NULL))
 314                return -EIO;
 315        status = be32_to_cpup(p);
 316
 317        for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) {
 318                if (mnt_errtbl[i].status == status) {
 319                        res->errno = mnt_errtbl[i].errno;
 320                        return 0;
 321                }
 322        }
 323
 324        dprintk("NFS: unrecognized MNT status code: %u\n", status);
 325        res->errno = -EACCES;
 326        return 0;
 327}
 328
 329static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
 330{
 331        struct nfs_fh *fh = res->fh;
 332        __be32 *p;
 333
 334        p = xdr_inline_decode(xdr, NFS2_FHSIZE);
 335        if (unlikely(p == NULL))
 336                return -EIO;
 337
 338        fh->size = NFS2_FHSIZE;
 339        memcpy(fh->data, p, NFS2_FHSIZE);
 340        return 0;
 341}
 342
 343static int mnt_xdr_dec_mountres(struct rpc_rqst *req,
 344                                struct xdr_stream *xdr,
 345                                struct mountres *res)
 346{
 347        int status;
 348
 349        status = decode_status(xdr, res);
 350        if (unlikely(status != 0 || res->errno != 0))
 351                return status;
 352        return decode_fhandle(xdr, res);
 353}
 354
 355static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)
 356{
 357        unsigned int i;
 358        u32 status;
 359        __be32 *p;
 360
 361        p = xdr_inline_decode(xdr, 4);
 362        if (unlikely(p == NULL))
 363                return -EIO;
 364        status = be32_to_cpup(p);
 365
 366        for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) {
 367                if (mnt3_errtbl[i].status == status) {
 368                        res->errno = mnt3_errtbl[i].errno;
 369                        return 0;
 370                }
 371        }
 372
 373        dprintk("NFS: unrecognized MNT3 status code: %u\n", status);
 374        res->errno = -EACCES;
 375        return 0;
 376}
 377
 378static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res)
 379{
 380        struct nfs_fh *fh = res->fh;
 381        u32 size;
 382        __be32 *p;
 383
 384        p = xdr_inline_decode(xdr, 4);
 385        if (unlikely(p == NULL))
 386                return -EIO;
 387
 388        size = be32_to_cpup(p);
 389        if (size > NFS3_FHSIZE || size == 0)
 390                return -EIO;
 391
 392        p = xdr_inline_decode(xdr, size);
 393        if (unlikely(p == NULL))
 394                return -EIO;
 395
 396        fh->size = size;
 397        memcpy(fh->data, p, size);
 398        return 0;
 399}
 400
 401static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
 402{
 403        rpc_authflavor_t *flavors = res->auth_flavors;
 404        unsigned int *count = res->auth_count;
 405        u32 entries, i;
 406        __be32 *p;
 407
 408        if (*count == 0)
 409                return 0;
 410
 411        p = xdr_inline_decode(xdr, 4);
 412        if (unlikely(p == NULL))
 413                return -EIO;
 414        entries = be32_to_cpup(p);
 415        dprintk("NFS: received %u auth flavors\n", entries);
 416        if (entries > NFS_MAX_SECFLAVORS)
 417                entries = NFS_MAX_SECFLAVORS;
 418
 419        p = xdr_inline_decode(xdr, 4 * entries);
 420        if (unlikely(p == NULL))
 421                return -EIO;
 422
 423        if (entries > *count)
 424                entries = *count;
 425
 426        for (i = 0; i < entries; i++) {
 427                flavors[i] = be32_to_cpup(p++);
 428                dprintk("NFS:   auth flavor[%u]: %d\n", i, flavors[i]);
 429        }
 430        *count = i;
 431
 432        return 0;
 433}
 434
 435static int mnt_xdr_dec_mountres3(struct rpc_rqst *req,
 436                                 struct xdr_stream *xdr,
 437                                 struct mountres *res)
 438{
 439        int status;
 440
 441        status = decode_fhs_status(xdr, res);
 442        if (unlikely(status != 0 || res->errno != 0))
 443                return status;
 444        status = decode_fhandle3(xdr, res);
 445        if (unlikely(status != 0)) {
 446                res->errno = -EBADHANDLE;
 447                return 0;
 448        }
 449        return decode_auth_flavors(xdr, res);
 450}
 451
 452static struct rpc_procinfo mnt_procedures[] = {
 453        [MOUNTPROC_MNT] = {
 454                .p_proc         = MOUNTPROC_MNT,
 455                .p_encode       = (kxdreproc_t)mnt_xdr_enc_dirpath,
 456                .p_decode       = (kxdrdproc_t)mnt_xdr_dec_mountres,
 457                .p_arglen       = MNT_enc_dirpath_sz,
 458                .p_replen       = MNT_dec_mountres_sz,
 459                .p_statidx      = MOUNTPROC_MNT,
 460                .p_name         = "MOUNT",
 461        },
 462        [MOUNTPROC_UMNT] = {
 463                .p_proc         = MOUNTPROC_UMNT,
 464                .p_encode       = (kxdreproc_t)mnt_xdr_enc_dirpath,
 465                .p_arglen       = MNT_enc_dirpath_sz,
 466                .p_statidx      = MOUNTPROC_UMNT,
 467                .p_name         = "UMOUNT",
 468        },
 469};
 470
 471static struct rpc_procinfo mnt3_procedures[] = {
 472        [MOUNTPROC3_MNT] = {
 473                .p_proc         = MOUNTPROC3_MNT,
 474                .p_encode       = (kxdreproc_t)mnt_xdr_enc_dirpath,
 475                .p_decode       = (kxdrdproc_t)mnt_xdr_dec_mountres3,
 476                .p_arglen       = MNT_enc_dirpath_sz,
 477                .p_replen       = MNT_dec_mountres3_sz,
 478                .p_statidx      = MOUNTPROC3_MNT,
 479                .p_name         = "MOUNT",
 480        },
 481        [MOUNTPROC3_UMNT] = {
 482                .p_proc         = MOUNTPROC3_UMNT,
 483                .p_encode       = (kxdreproc_t)mnt_xdr_enc_dirpath,
 484                .p_arglen       = MNT_enc_dirpath_sz,
 485                .p_statidx      = MOUNTPROC3_UMNT,
 486                .p_name         = "UMOUNT",
 487        },
 488};
 489
 490
 491static const struct rpc_version mnt_version1 = {
 492        .number         = 1,
 493        .nrprocs        = ARRAY_SIZE(mnt_procedures),
 494        .procs          = mnt_procedures,
 495};
 496
 497static const struct rpc_version mnt_version3 = {
 498        .number         = 3,
 499        .nrprocs        = ARRAY_SIZE(mnt3_procedures),
 500        .procs          = mnt3_procedures,
 501};
 502
 503static const struct rpc_version *mnt_version[] = {
 504        NULL,
 505        &mnt_version1,
 506        NULL,
 507        &mnt_version3,
 508};
 509
 510static struct rpc_stat mnt_stats;
 511
 512static const struct rpc_program mnt_program = {
 513        .name           = "mount",
 514        .number         = NFS_MNT_PROGRAM,
 515        .nrvers         = ARRAY_SIZE(mnt_version),
 516        .version        = mnt_version,
 517        .stats          = &mnt_stats,
 518};
 519
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.