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