linux/fs/nfs/nfs42proc.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com>
   3 */
   4#include <linux/fs.h>
   5#include <linux/sunrpc/sched.h>
   6#include <linux/nfs.h>
   7#include <linux/nfs3.h>
   8#include <linux/nfs4.h>
   9#include <linux/nfs_xdr.h>
  10#include <linux/nfs_fs.h>
  11#include "nfs4_fs.h"
  12#include "nfs42.h"
  13#include "iostat.h"
  14#include "pnfs.h"
  15#include "nfs4session.h"
  16#include "internal.h"
  17
  18#define NFSDBG_FACILITY NFSDBG_PROC
  19
  20static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
  21                struct nfs_lock_context *lock, loff_t offset, loff_t len)
  22{
  23        struct inode *inode = file_inode(filep);
  24        struct nfs_server *server = NFS_SERVER(inode);
  25        struct nfs42_falloc_args args = {
  26                .falloc_fh      = NFS_FH(inode),
  27                .falloc_offset  = offset,
  28                .falloc_length  = len,
  29                .falloc_bitmask = server->cache_consistency_bitmask,
  30        };
  31        struct nfs42_falloc_res res = {
  32                .falloc_server  = server,
  33        };
  34        int status;
  35
  36        msg->rpc_argp = &args;
  37        msg->rpc_resp = &res;
  38
  39        status = nfs4_set_rw_stateid(&args.falloc_stateid, lock->open_context,
  40                        lock, FMODE_WRITE);
  41        if (status)
  42                return status;
  43
  44        res.falloc_fattr = nfs_alloc_fattr();
  45        if (!res.falloc_fattr)
  46                return -ENOMEM;
  47
  48        status = nfs4_call_sync(server->client, server, msg,
  49                                &args.seq_args, &res.seq_res, 0);
  50        if (status == 0)
  51                status = nfs_post_op_update_inode(inode, res.falloc_fattr);
  52
  53        kfree(res.falloc_fattr);
  54        return status;
  55}
  56
  57static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
  58                                loff_t offset, loff_t len)
  59{
  60        struct nfs_server *server = NFS_SERVER(file_inode(filep));
  61        struct nfs4_exception exception = { };
  62        struct nfs_lock_context *lock;
  63        int err;
  64
  65        lock = nfs_get_lock_context(nfs_file_open_context(filep));
  66        if (IS_ERR(lock))
  67                return PTR_ERR(lock);
  68
  69        exception.inode = file_inode(filep);
  70        exception.state = lock->open_context->state;
  71
  72        do {
  73                err = _nfs42_proc_fallocate(msg, filep, lock, offset, len);
  74                if (err == -ENOTSUPP) {
  75                        err = -EOPNOTSUPP;
  76                        break;
  77                }
  78                err = nfs4_handle_exception(server, err, &exception);
  79        } while (exception.retry);
  80
  81        nfs_put_lock_context(lock);
  82        return err;
  83}
  84
  85int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len)
  86{
  87        struct rpc_message msg = {
  88                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE],
  89        };
  90        struct inode *inode = file_inode(filep);
  91        int err;
  92
  93        if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE))
  94                return -EOPNOTSUPP;
  95
  96        inode_lock(inode);
  97
  98        err = nfs42_proc_fallocate(&msg, filep, offset, len);
  99        if (err == -EOPNOTSUPP)
 100                NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE;
 101
 102        inode_unlock(inode);
 103        return err;
 104}
 105
 106int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
 107{
 108        struct rpc_message msg = {
 109                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DEALLOCATE],
 110        };
 111        struct inode *inode = file_inode(filep);
 112        int err;
 113
 114        if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE))
 115                return -EOPNOTSUPP;
 116
 117        inode_lock(inode);
 118        err = nfs_sync_inode(inode);
 119        if (err)
 120                goto out_unlock;
 121
 122        err = nfs42_proc_fallocate(&msg, filep, offset, len);
 123        if (err == 0)
 124                truncate_pagecache_range(inode, offset, (offset + len) -1);
 125        if (err == -EOPNOTSUPP)
 126                NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE;
 127out_unlock:
 128        inode_unlock(inode);
 129        return err;
 130}
 131
 132static ssize_t _nfs42_proc_copy(struct file *src,
 133                                struct nfs_lock_context *src_lock,
 134                                struct file *dst,
 135                                struct nfs_lock_context *dst_lock,
 136                                struct nfs42_copy_args *args,
 137                                struct nfs42_copy_res *res)
 138{
 139        struct rpc_message msg = {
 140                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
 141                .rpc_argp = args,
 142                .rpc_resp = res,
 143        };
 144        struct inode *dst_inode = file_inode(dst);
 145        struct nfs_server *server = NFS_SERVER(dst_inode);
 146        loff_t pos_src = args->src_pos;
 147        loff_t pos_dst = args->dst_pos;
 148        size_t count = args->count;
 149        ssize_t status;
 150
 151        status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
 152                                     src_lock, FMODE_READ);
 153        if (status)
 154                return status;
 155
 156        status = nfs_filemap_write_and_wait_range(file_inode(src)->i_mapping,
 157                        pos_src, pos_src + (loff_t)count - 1);
 158        if (status)
 159                return status;
 160
 161        status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context,
 162                                     dst_lock, FMODE_WRITE);
 163        if (status)
 164                return status;
 165
 166        status = nfs_sync_inode(dst_inode);
 167        if (status)
 168                return status;
 169
 170        res->commit_res.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
 171        if (!res->commit_res.verf)
 172                return -ENOMEM;
 173        status = nfs4_call_sync(server->client, server, &msg,
 174                                &args->seq_args, &res->seq_res, 0);
 175        if (status == -ENOTSUPP)
 176                server->caps &= ~NFS_CAP_COPY;
 177        if (status)
 178                goto out;
 179
 180        if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
 181                                    &res->commit_res.verf->verifier)) {
 182                status = -EAGAIN;
 183                goto out;
 184        }
 185
 186        truncate_pagecache_range(dst_inode, pos_dst,
 187                                 pos_dst + res->write_res.count);
 188
 189        status = res->write_res.count;
 190out:
 191        kfree(res->commit_res.verf);
 192        return status;
 193}
 194
 195ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
 196                        struct file *dst, loff_t pos_dst,
 197                        size_t count)
 198{
 199        struct nfs_server *server = NFS_SERVER(file_inode(dst));
 200        struct nfs_lock_context *src_lock;
 201        struct nfs_lock_context *dst_lock;
 202        struct nfs42_copy_args args = {
 203                .src_fh         = NFS_FH(file_inode(src)),
 204                .src_pos        = pos_src,
 205                .dst_fh         = NFS_FH(file_inode(dst)),
 206                .dst_pos        = pos_dst,
 207                .count          = count,
 208        };
 209        struct nfs42_copy_res res;
 210        struct nfs4_exception src_exception = {
 211                .inode          = file_inode(src),
 212                .stateid        = &args.src_stateid,
 213        };
 214        struct nfs4_exception dst_exception = {
 215                .inode          = file_inode(dst),
 216                .stateid        = &args.dst_stateid,
 217        };
 218        ssize_t err, err2;
 219
 220        if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY))
 221                return -EOPNOTSUPP;
 222
 223        src_lock = nfs_get_lock_context(nfs_file_open_context(src));
 224        if (IS_ERR(src_lock))
 225                return PTR_ERR(src_lock);
 226
 227        src_exception.state = src_lock->open_context->state;
 228
 229        dst_lock = nfs_get_lock_context(nfs_file_open_context(dst));
 230        if (IS_ERR(dst_lock)) {
 231                err = PTR_ERR(dst_lock);
 232                goto out_put_src_lock;
 233        }
 234
 235        dst_exception.state = dst_lock->open_context->state;
 236
 237        do {
 238                inode_lock(file_inode(dst));
 239                err = _nfs42_proc_copy(src, src_lock,
 240                                dst, dst_lock,
 241                                &args, &res);
 242                inode_unlock(file_inode(dst));
 243
 244                if (err >= 0)
 245                        break;
 246                if (err == -ENOTSUPP) {
 247                        err = -EOPNOTSUPP;
 248                        break;
 249                } if (err == -EAGAIN) {
 250                        dst_exception.retry = 1;
 251                        continue;
 252                }
 253
 254                err2 = nfs4_handle_exception(server, err, &src_exception);
 255                err  = nfs4_handle_exception(server, err, &dst_exception);
 256                if (!err)
 257                        err = err2;
 258        } while (src_exception.retry || dst_exception.retry);
 259
 260        nfs_put_lock_context(dst_lock);
 261out_put_src_lock:
 262        nfs_put_lock_context(src_lock);
 263        return err;
 264}
 265
 266static loff_t _nfs42_proc_llseek(struct file *filep,
 267                struct nfs_lock_context *lock, loff_t offset, int whence)
 268{
 269        struct inode *inode = file_inode(filep);
 270        struct nfs42_seek_args args = {
 271                .sa_fh          = NFS_FH(inode),
 272                .sa_offset      = offset,
 273                .sa_what        = (whence == SEEK_HOLE) ?
 274                                        NFS4_CONTENT_HOLE : NFS4_CONTENT_DATA,
 275        };
 276        struct nfs42_seek_res res;
 277        struct rpc_message msg = {
 278                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEEK],
 279                .rpc_argp = &args,
 280                .rpc_resp = &res,
 281        };
 282        struct nfs_server *server = NFS_SERVER(inode);
 283        int status;
 284
 285        if (!nfs_server_capable(inode, NFS_CAP_SEEK))
 286                return -ENOTSUPP;
 287
 288        status = nfs4_set_rw_stateid(&args.sa_stateid, lock->open_context,
 289                        lock, FMODE_READ);
 290        if (status)
 291                return status;
 292
 293        status = nfs_filemap_write_and_wait_range(inode->i_mapping,
 294                        offset, LLONG_MAX);
 295        if (status)
 296                return status;
 297
 298        status = nfs4_call_sync(server->client, server, &msg,
 299                                &args.seq_args, &res.seq_res, 0);
 300        if (status == -ENOTSUPP)
 301                server->caps &= ~NFS_CAP_SEEK;
 302        if (status)
 303                return status;
 304
 305        return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
 306}
 307
 308loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
 309{
 310        struct nfs_server *server = NFS_SERVER(file_inode(filep));
 311        struct nfs4_exception exception = { };
 312        struct nfs_lock_context *lock;
 313        loff_t err;
 314
 315        lock = nfs_get_lock_context(nfs_file_open_context(filep));
 316        if (IS_ERR(lock))
 317                return PTR_ERR(lock);
 318
 319        exception.inode = file_inode(filep);
 320        exception.state = lock->open_context->state;
 321
 322        do {
 323                err = _nfs42_proc_llseek(filep, lock, offset, whence);
 324                if (err >= 0)
 325                        break;
 326                if (err == -ENOTSUPP) {
 327                        err = -EOPNOTSUPP;
 328                        break;
 329                }
 330                err = nfs4_handle_exception(server, err, &exception);
 331        } while (exception.retry);
 332
 333        nfs_put_lock_context(lock);
 334        return err;
 335}
 336
 337
 338static void
 339nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
 340{
 341        struct nfs42_layoutstat_data *data = calldata;
 342        struct inode *inode = data->inode;
 343        struct nfs_server *server = NFS_SERVER(inode);
 344        struct pnfs_layout_hdr *lo;
 345
 346        spin_lock(&inode->i_lock);
 347        lo = NFS_I(inode)->layout;
 348        if (!pnfs_layout_is_valid(lo)) {
 349                spin_unlock(&inode->i_lock);
 350                rpc_exit(task, 0);
 351                return;
 352        }
 353        nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid);
 354        spin_unlock(&inode->i_lock);
 355        nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
 356                            &data->res.seq_res, task);
 357}
 358
 359static void
 360nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
 361{
 362        struct nfs42_layoutstat_data *data = calldata;
 363        struct inode *inode = data->inode;
 364        struct pnfs_layout_hdr *lo;
 365
 366        if (!nfs4_sequence_done(task, &data->res.seq_res))
 367                return;
 368
 369        switch (task->tk_status) {
 370        case 0:
 371                break;
 372        case -NFS4ERR_EXPIRED:
 373        case -NFS4ERR_ADMIN_REVOKED:
 374        case -NFS4ERR_DELEG_REVOKED:
 375        case -NFS4ERR_STALE_STATEID:
 376        case -NFS4ERR_BAD_STATEID:
 377                spin_lock(&inode->i_lock);
 378                lo = NFS_I(inode)->layout;
 379                if (pnfs_layout_is_valid(lo) &&
 380                    nfs4_stateid_match(&data->args.stateid,
 381                                             &lo->plh_stateid)) {
 382                        LIST_HEAD(head);
 383
 384                        /*
 385                         * Mark the bad layout state as invalid, then retry
 386                         * with the current stateid.
 387                         */
 388                        pnfs_mark_layout_stateid_invalid(lo, &head);
 389                        spin_unlock(&inode->i_lock);
 390                        pnfs_free_lseg_list(&head);
 391                        nfs_commit_inode(inode, 0);
 392                } else
 393                        spin_unlock(&inode->i_lock);
 394                break;
 395        case -NFS4ERR_OLD_STATEID:
 396                spin_lock(&inode->i_lock);
 397                lo = NFS_I(inode)->layout;
 398                if (pnfs_layout_is_valid(lo) &&
 399                    nfs4_stateid_match_other(&data->args.stateid,
 400                                        &lo->plh_stateid)) {
 401                        /* Do we need to delay before resending? */
 402                        if (!nfs4_stateid_is_newer(&lo->plh_stateid,
 403                                                &data->args.stateid))
 404                                rpc_delay(task, HZ);
 405                        rpc_restart_call_prepare(task);
 406                }
 407                spin_unlock(&inode->i_lock);
 408                break;
 409        case -ENOTSUPP:
 410        case -EOPNOTSUPP:
 411                NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
 412        }
 413}
 414
 415static void
 416nfs42_layoutstat_release(void *calldata)
 417{
 418        struct nfs42_layoutstat_data *data = calldata;
 419        struct nfs42_layoutstat_devinfo *devinfo = data->args.devinfo;
 420        int i;
 421
 422        for (i = 0; i < data->args.num_dev; i++) {
 423                if (devinfo[i].ld_private.ops && devinfo[i].ld_private.ops->free)
 424                        devinfo[i].ld_private.ops->free(&devinfo[i].ld_private);
 425        }
 426
 427        pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout);
 428        smp_mb__before_atomic();
 429        clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags);
 430        smp_mb__after_atomic();
 431        nfs_iput_and_deactive(data->inode);
 432        kfree(data->args.devinfo);
 433        kfree(data);
 434}
 435
 436static const struct rpc_call_ops nfs42_layoutstat_ops = {
 437        .rpc_call_prepare = nfs42_layoutstat_prepare,
 438        .rpc_call_done = nfs42_layoutstat_done,
 439        .rpc_release = nfs42_layoutstat_release,
 440};
 441
 442int nfs42_proc_layoutstats_generic(struct nfs_server *server,
 443                                   struct nfs42_layoutstat_data *data)
 444{
 445        struct rpc_message msg = {
 446                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTSTATS],
 447                .rpc_argp = &data->args,
 448                .rpc_resp = &data->res,
 449        };
 450        struct rpc_task_setup task_setup = {
 451                .rpc_client = server->client,
 452                .rpc_message = &msg,
 453                .callback_ops = &nfs42_layoutstat_ops,
 454                .callback_data = data,
 455                .flags = RPC_TASK_ASYNC,
 456        };
 457        struct rpc_task *task;
 458
 459        data->inode = nfs_igrab_and_active(data->args.inode);
 460        if (!data->inode) {
 461                nfs42_layoutstat_release(data);
 462                return -EAGAIN;
 463        }
 464        nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
 465        task = rpc_run_task(&task_setup);
 466        if (IS_ERR(task))
 467                return PTR_ERR(task);
 468        rpc_put_task(task);
 469        return 0;
 470}
 471
 472static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
 473                struct file *dst_f, struct nfs_lock_context *src_lock,
 474                struct nfs_lock_context *dst_lock, loff_t src_offset,
 475                loff_t dst_offset, loff_t count)
 476{
 477        struct inode *src_inode = file_inode(src_f);
 478        struct inode *dst_inode = file_inode(dst_f);
 479        struct nfs_server *server = NFS_SERVER(dst_inode);
 480        struct nfs42_clone_args args = {
 481                .src_fh = NFS_FH(src_inode),
 482                .dst_fh = NFS_FH(dst_inode),
 483                .src_offset = src_offset,
 484                .dst_offset = dst_offset,
 485                .count = count,
 486                .dst_bitmask = server->cache_consistency_bitmask,
 487        };
 488        struct nfs42_clone_res res = {
 489                .server = server,
 490        };
 491        int status;
 492
 493        msg->rpc_argp = &args;
 494        msg->rpc_resp = &res;
 495
 496        status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
 497                        src_lock, FMODE_READ);
 498        if (status)
 499                return status;
 500
 501        status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
 502                        dst_lock, FMODE_WRITE);
 503        if (status)
 504                return status;
 505
 506        res.dst_fattr = nfs_alloc_fattr();
 507        if (!res.dst_fattr)
 508                return -ENOMEM;
 509
 510        status = nfs4_call_sync(server->client, server, msg,
 511                                &args.seq_args, &res.seq_res, 0);
 512        if (status == 0)
 513                status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
 514
 515        kfree(res.dst_fattr);
 516        return status;
 517}
 518
 519int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
 520                     loff_t src_offset, loff_t dst_offset, loff_t count)
 521{
 522        struct rpc_message msg = {
 523                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE],
 524        };
 525        struct inode *inode = file_inode(src_f);
 526        struct nfs_server *server = NFS_SERVER(file_inode(src_f));
 527        struct nfs_lock_context *src_lock;
 528        struct nfs_lock_context *dst_lock;
 529        struct nfs4_exception src_exception = { };
 530        struct nfs4_exception dst_exception = { };
 531        int err, err2;
 532
 533        if (!nfs_server_capable(inode, NFS_CAP_CLONE))
 534                return -EOPNOTSUPP;
 535
 536        src_lock = nfs_get_lock_context(nfs_file_open_context(src_f));
 537        if (IS_ERR(src_lock))
 538                return PTR_ERR(src_lock);
 539
 540        src_exception.inode = file_inode(src_f);
 541        src_exception.state = src_lock->open_context->state;
 542
 543        dst_lock = nfs_get_lock_context(nfs_file_open_context(dst_f));
 544        if (IS_ERR(dst_lock)) {
 545                err = PTR_ERR(dst_lock);
 546                goto out_put_src_lock;
 547        }
 548
 549        dst_exception.inode = file_inode(dst_f);
 550        dst_exception.state = dst_lock->open_context->state;
 551
 552        do {
 553                err = _nfs42_proc_clone(&msg, src_f, dst_f, src_lock, dst_lock,
 554                                        src_offset, dst_offset, count);
 555                if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
 556                        NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
 557                        err = -EOPNOTSUPP;
 558                        break;
 559                }
 560
 561                err2 = nfs4_handle_exception(server, err, &src_exception);
 562                err = nfs4_handle_exception(server, err, &dst_exception);
 563                if (!err)
 564                        err = err2;
 565        } while (src_exception.retry || dst_exception.retry);
 566
 567        nfs_put_lock_context(dst_lock);
 568out_put_src_lock:
 569        nfs_put_lock_context(src_lock);
 570        return err;
 571}
 572