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 RPC_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 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 = -ESERVERFAULT, },
 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                .protocol       = info->protocol,
 157                .address        = info->sap,
 158                .addrsize       = info->salen,
 159                .servername     = info->hostname,
 160                .program        = &mnt_program,
 161                .version        = info->version,
 162                .authflavor     = RPC_AUTH_UNIX,
 163        };
 164        struct rpc_clnt         *mnt_clnt;
 165        int                     status;
 166
 167        dprintk("NFS: sending MNT request for %s:%s\n",
 168                (info->hostname ? info->hostname : "server"),
 169                        info->dirpath);
 170
 171        if (info->noresvport)
 172                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 173
 174        mnt_clnt = rpc_create(&args);
 175        if (IS_ERR(mnt_clnt))
 176                goto out_clnt_err;
 177
 178        if (info->version == NFS_MNT3_VERSION)
 179                msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
 180        else
 181                msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
 182
 183        status = rpc_call_sync(mnt_clnt, &msg, 0);
 184        rpc_shutdown_client(mnt_clnt);
 185
 186        if (status < 0)
 187                goto out_call_err;
 188        if (result.errno != 0)
 189                goto out_mnt_err;
 190
 191        dprintk("NFS: MNT request succeeded\n");
 192        status = 0;
 193
 194out:
 195        return status;
 196
 197out_clnt_err:
 198        status = PTR_ERR(mnt_clnt);
 199        dprintk("NFS: failed to create MNT RPC client, status=%d\n", status);
 200        goto out;
 201
 202out_call_err:
 203        dprintk("NFS: MNT request failed, status=%d\n", status);
 204        goto out;
 205
 206out_mnt_err:
 207        dprintk("NFS: MNT server returned result %d\n", result.errno);
 208        status = result.errno;
 209        goto out;
 210}
 211
 212/**
 213 * nfs_umount - Notify a server that we have unmounted this export
 214 * @info: pointer to umount request arguments
 215 *
 216 * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
 217 * use UDP.
 218 */
 219void nfs_umount(const struct nfs_mount_request *info)
 220{
 221        static const struct rpc_timeout nfs_umnt_timeout = {
 222                .to_initval = 1 * HZ,
 223                .to_maxval = 3 * HZ,
 224                .to_retries = 2,
 225        };
 226        struct rpc_create_args args = {
 227                .protocol       = IPPROTO_UDP,
 228                .address        = info->sap,
 229                .addrsize       = info->salen,
 230                .timeout        = &nfs_umnt_timeout,
 231                .servername     = info->hostname,
 232                .program        = &mnt_program,
 233                .version        = info->version,
 234                .authflavor     = RPC_AUTH_UNIX,
 235                .flags          = RPC_CLNT_CREATE_NOPING,
 236        };
 237        struct mountres result;
 238        struct rpc_message msg  = {
 239                .rpc_argp       = info->dirpath,
 240                .rpc_resp       = &result,
 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 (unlikely(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 int encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
 282{
 283        const u32 pathname_len = strlen(pathname);
 284        __be32 *p;
 285
 286        if (unlikely(pathname_len > MNTPATHLEN))
 287                return -EIO;
 288
 289        p = xdr_reserve_space(xdr, sizeof(u32) + pathname_len);
 290        if (unlikely(p == NULL))
 291                return -EIO;
 292        xdr_encode_opaque(p, pathname, pathname_len);
 293
 294        return 0;
 295}
 296
 297static int mnt_enc_dirpath(struct rpc_rqst *req, __be32 *p,
 298                           const char *dirpath)
 299{
 300        struct xdr_stream xdr;
 301
 302        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 303        return encode_mntdirpath(&xdr, dirpath);
 304}
 305
 306/*
 307 * RFC 1094: "A non-zero status indicates some sort of error.  In this
 308 * case, the status is a UNIX error number."  This can be problematic
 309 * if the server and client use different errno values for the same
 310 * error.
 311 *
 312 * However, the OpenGroup XNFS spec provides a simple mapping that is
 313 * independent of local errno values on the server and the client.
 314 */
 315static int decode_status(struct xdr_stream *xdr, struct mountres *res)
 316{
 317        unsigned int i;
 318        u32 status;
 319        __be32 *p;
 320
 321        p = xdr_inline_decode(xdr, sizeof(status));
 322        if (unlikely(p == NULL))
 323                return -EIO;
 324        status = ntohl(*p);
 325
 326        for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) {
 327                if (mnt_errtbl[i].status == status) {
 328                        res->errno = mnt_errtbl[i].errno;
 329                        return 0;
 330                }
 331        }
 332
 333        dprintk("NFS: unrecognized MNT status code: %u\n", status);
 334        res->errno = -EACCES;
 335        return 0;
 336}
 337
 338static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
 339{
 340        struct nfs_fh *fh = res->fh;
 341        __be32 *p;
 342
 343        p = xdr_inline_decode(xdr, NFS2_FHSIZE);
 344        if (unlikely(p == NULL))
 345                return -EIO;
 346
 347        fh->size = NFS2_FHSIZE;
 348        memcpy(fh->data, p, NFS2_FHSIZE);
 349        return 0;
 350}
 351
 352static int mnt_dec_mountres(struct rpc_rqst *req, __be32 *p,
 353                            struct mountres *res)
 354{
 355        struct xdr_stream xdr;
 356        int status;
 357
 358        xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
 359
 360        status = decode_status(&xdr, res);
 361        if (unlikely(status != 0 || res->errno != 0))
 362                return status;
 363        return decode_fhandle(&xdr, res);
 364}
 365
 366static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)
 367{
 368        unsigned int i;
 369        u32 status;
 370        __be32 *p;
 371
 372        p = xdr_inline_decode(xdr, sizeof(status));
 373        if (unlikely(p == NULL))
 374                return -EIO;
 375        status = ntohl(*p);
 376
 377        for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) {
 378                if (mnt3_errtbl[i].status == status) {
 379                        res->errno = mnt3_errtbl[i].errno;
 380                        return 0;
 381                }
 382        }
 383
 384        dprintk("NFS: unrecognized MNT3 status code: %u\n", status);
 385        res->errno = -EACCES;
 386        return 0;
 387}
 388
 389static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res)
 390{
 391        struct nfs_fh *fh = res->fh;
 392        u32 size;
 393        __be32 *p;
 394
 395        p = xdr_inline_decode(xdr, sizeof(size));
 396        if (unlikely(p == NULL))
 397                return -EIO;
 398
 399        size = ntohl(*p++);
 400        if (size > NFS3_FHSIZE || size == 0)
 401                return -EIO;
 402
 403        p = xdr_inline_decode(xdr, size);
 404        if (unlikely(p == NULL))
 405                return -EIO;
 406
 407        fh->size = size;
 408        memcpy(fh->data, p, size);
 409        return 0;
 410}
 411
 412static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
 413{
 414        rpc_authflavor_t *flavors = res->auth_flavors;
 415        unsigned int *count = res->auth_count;
 416        u32 entries, i;
 417        __be32 *p;
 418
 419        if (*count == 0)
 420                return 0;
 421
 422        p = xdr_inline_decode(xdr, sizeof(entries));
 423        if (unlikely(p == NULL))
 424                return -EIO;
 425        entries = ntohl(*p);
 426        dprintk("NFS: received %u auth flavors\n", entries);
 427        if (entries > NFS_MAX_SECFLAVORS)
 428                entries = NFS_MAX_SECFLAVORS;
 429
 430        p = xdr_inline_decode(xdr, sizeof(u32) * entries);
 431        if (unlikely(p == NULL))
 432                return -EIO;
 433
 434        if (entries > *count)
 435                entries = *count;
 436
 437        for (i = 0; i < entries; i++) {
 438                flavors[i] = ntohl(*p++);
 439                dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]);
 440        }
 441        *count = i;
 442
 443        return 0;
 444}
 445
 446static int mnt_dec_mountres3(struct rpc_rqst *req, __be32 *p,
 447                             struct mountres *res)
 448{
 449        struct xdr_stream xdr;
 450        int status;
 451
 452        xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
 453
 454        status = decode_fhs_status(&xdr, res);
 455        if (unlikely(status != 0 || res->errno != 0))
 456                return status;
 457        status = decode_fhandle3(&xdr, res);
 458        if (unlikely(status != 0)) {
 459                res->errno = -EBADHANDLE;
 460                return 0;
 461        }
 462        return decode_auth_flavors(&xdr, res);
 463}
 464
 465static struct rpc_procinfo mnt_procedures[] = {
 466        [MOUNTPROC_MNT] = {
 467                .p_proc         = MOUNTPROC_MNT,
 468                .p_encode       = (kxdrproc_t)mnt_enc_dirpath,
 469                .p_decode       = (kxdrproc_t)mnt_dec_mountres,
 470                .p_arglen       = MNT_enc_dirpath_sz,
 471                .p_replen       = MNT_dec_mountres_sz,
 472                .p_statidx      = MOUNTPROC_MNT,
 473                .p_name         = "MOUNT",
 474        },
 475        [MOUNTPROC_UMNT] = {
 476                .p_proc         = MOUNTPROC_UMNT,
 477                .p_encode       = (kxdrproc_t)mnt_enc_dirpath,
 478                .p_arglen       = MNT_enc_dirpath_sz,
 479                .p_statidx      = MOUNTPROC_UMNT,
 480                .p_name         = "UMOUNT",
 481        },
 482};
 483
 484static struct rpc_procinfo mnt3_procedures[] = {
 485        [MOUNTPROC3_MNT] = {
 486                .p_proc         = MOUNTPROC3_MNT,
 487                .p_encode       = (kxdrproc_t)mnt_enc_dirpath,
 488                .p_decode       = (kxdrproc_t)mnt_dec_mountres3,
 489                .p_arglen       = MNT_enc_dirpath_sz,
 490                .p_replen       = MNT_dec_mountres3_sz,
 491                .p_statidx      = MOUNTPROC3_MNT,
 492                .p_name         = "MOUNT",
 493        },
 494        [MOUNTPROC3_UMNT] = {
 495                .p_proc         = MOUNTPROC3_UMNT,
 496                .p_encode       = (kxdrproc_t)mnt_enc_dirpath,
 497                .p_arglen       = MNT_enc_dirpath_sz,
 498                .p_statidx      = MOUNTPROC3_UMNT,
 499                .p_name         = "UMOUNT",
 500        },
 501};
 502
 503
 504static struct rpc_version mnt_version1 = {
 505        .number         = 1,
 506        .nrprocs        = 2,
 507        .procs          = mnt_procedures,
 508};
 509
 510static struct rpc_version mnt_version3 = {
 511        .number         = 3,
 512        .nrprocs        = 2,
 513        .procs          = mnt3_procedures,
 514};
 515
 516static struct rpc_version *mnt_version[] = {
 517        NULL,
 518        &mnt_version1,
 519        NULL,
 520        &mnt_version3,
 521};
 522
 523static struct rpc_stat mnt_stats;
 524
 525static struct rpc_program mnt_program = {
 526        .name           = "mount",
 527        .number         = NFS_MNT_PROGRAM,
 528        .nrvers         = ARRAY_SIZE(mnt_version),
 529        .version        = mnt_version,
 530        .stats          = &mnt_stats,
 531};
 532