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