linux/fs/nfs/delegation.c
<<
>>
Prefs
   1/*
   2 * linux/fs/nfs/delegation.c
   3 *
   4 * Copyright (C) 2004 Trond Myklebust
   5 *
   6 * NFS file delegation management
   7 *
   8 */
   9#include <linux/completion.h>
  10#include <linux/kthread.h>
  11#include <linux/module.h>
  12#include <linux/sched.h>
  13#include <linux/smp_lock.h>
  14#include <linux/spinlock.h>
  15
  16#include <linux/nfs4.h>
  17#include <linux/nfs_fs.h>
  18#include <linux/nfs_xdr.h>
  19
  20#include "nfs4_fs.h"
  21#include "delegation.h"
  22#include "internal.h"
  23
  24static void nfs_do_free_delegation(struct nfs_delegation *delegation)
  25{
  26        kfree(delegation);
  27}
  28
  29static void nfs_free_delegation_callback(struct rcu_head *head)
  30{
  31        struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu);
  32
  33        nfs_do_free_delegation(delegation);
  34}
  35
  36static void nfs_free_delegation(struct nfs_delegation *delegation)
  37{
  38        struct rpc_cred *cred;
  39
  40        cred = rcu_dereference(delegation->cred);
  41        rcu_assign_pointer(delegation->cred, NULL);
  42        call_rcu(&delegation->rcu, nfs_free_delegation_callback);
  43        if (cred)
  44                put_rpccred(cred);
  45}
  46
  47void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
  48{
  49        set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
  50}
  51
  52int nfs_have_delegation(struct inode *inode, fmode_t flags)
  53{
  54        struct nfs_delegation *delegation;
  55        int ret = 0;
  56
  57        flags &= FMODE_READ|FMODE_WRITE;
  58        rcu_read_lock();
  59        delegation = rcu_dereference(NFS_I(inode)->delegation);
  60        if (delegation != NULL && (delegation->type & flags) == flags) {
  61                nfs_mark_delegation_referenced(delegation);
  62                ret = 1;
  63        }
  64        rcu_read_unlock();
  65        return ret;
  66}
  67
  68static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
  69{
  70        struct inode *inode = state->inode;
  71        struct file_lock *fl;
  72        int status = 0;
  73
  74        if (inode->i_flock == NULL)
  75                goto out;
  76
  77        /* Protect inode->i_flock using the BKL */
  78        lock_kernel();
  79        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
  80                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
  81                        continue;
  82                if (nfs_file_open_context(fl->fl_file) != ctx)
  83                        continue;
  84                unlock_kernel();
  85                status = nfs4_lock_delegation_recall(state, fl);
  86                if (status < 0)
  87                        goto out;
  88                lock_kernel();
  89        }
  90        unlock_kernel();
  91out:
  92        return status;
  93}
  94
  95static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
  96{
  97        struct nfs_inode *nfsi = NFS_I(inode);
  98        struct nfs_open_context *ctx;
  99        struct nfs4_state *state;
 100        int err;
 101
 102again:
 103        spin_lock(&inode->i_lock);
 104        list_for_each_entry(ctx, &nfsi->open_files, list) {
 105                state = ctx->state;
 106                if (state == NULL)
 107                        continue;
 108                if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
 109                        continue;
 110                if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
 111                        continue;
 112                get_nfs_open_context(ctx);
 113                spin_unlock(&inode->i_lock);
 114                err = nfs4_open_delegation_recall(ctx, state, stateid);
 115                if (err >= 0)
 116                        err = nfs_delegation_claim_locks(ctx, state);
 117                put_nfs_open_context(ctx);
 118                if (err != 0)
 119                        return;
 120                goto again;
 121        }
 122        spin_unlock(&inode->i_lock);
 123}
 124
 125/*
 126 * Set up a delegation on an inode
 127 */
 128void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
 129{
 130        struct nfs_delegation *delegation = NFS_I(inode)->delegation;
 131        struct rpc_cred *oldcred;
 132
 133        if (delegation == NULL)
 134                return;
 135        memcpy(delegation->stateid.data, res->delegation.data,
 136                        sizeof(delegation->stateid.data));
 137        delegation->type = res->delegation_type;
 138        delegation->maxsize = res->maxsize;
 139        oldcred = delegation->cred;
 140        delegation->cred = get_rpccred(cred);
 141        clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
 142        NFS_I(inode)->delegation_state = delegation->type;
 143        smp_wmb();
 144        put_rpccred(oldcred);
 145}
 146
 147static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
 148{
 149        int res = 0;
 150
 151        res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync);
 152        nfs_free_delegation(delegation);
 153        return res;
 154}
 155
 156static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation)
 157{
 158        struct inode *inode = NULL;
 159
 160        spin_lock(&delegation->lock);
 161        if (delegation->inode != NULL)
 162                inode = igrab(delegation->inode);
 163        spin_unlock(&delegation->lock);
 164        return inode;
 165}
 166
 167static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
 168{
 169        struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
 170
 171        if (delegation == NULL)
 172                goto nomatch;
 173        spin_lock(&delegation->lock);
 174        if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data,
 175                                sizeof(delegation->stateid.data)) != 0)
 176                goto nomatch_unlock;
 177        list_del_rcu(&delegation->super_list);
 178        delegation->inode = NULL;
 179        nfsi->delegation_state = 0;
 180        rcu_assign_pointer(nfsi->delegation, NULL);
 181        spin_unlock(&delegation->lock);
 182        return delegation;
 183nomatch_unlock:
 184        spin_unlock(&delegation->lock);
 185nomatch:
 186        return NULL;
 187}
 188
 189/*
 190 * Set up a delegation on an inode
 191 */
 192int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
 193{
 194        struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
 195        struct nfs_inode *nfsi = NFS_I(inode);
 196        struct nfs_delegation *delegation;
 197        struct nfs_delegation *freeme = NULL;
 198        int status = 0;
 199
 200        delegation = kmalloc(sizeof(*delegation), GFP_KERNEL);
 201        if (delegation == NULL)
 202                return -ENOMEM;
 203        memcpy(delegation->stateid.data, res->delegation.data,
 204                        sizeof(delegation->stateid.data));
 205        delegation->type = res->delegation_type;
 206        delegation->maxsize = res->maxsize;
 207        delegation->change_attr = nfsi->change_attr;
 208        delegation->cred = get_rpccred(cred);
 209        delegation->inode = inode;
 210        delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
 211        spin_lock_init(&delegation->lock);
 212
 213        spin_lock(&clp->cl_lock);
 214        if (rcu_dereference(nfsi->delegation) != NULL) {
 215                if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
 216                                        sizeof(delegation->stateid)) == 0 &&
 217                                delegation->type == nfsi->delegation->type) {
 218                        goto out;
 219                }
 220                /*
 221                 * Deal with broken servers that hand out two
 222                 * delegations for the same file.
 223                 */
 224                dfprintk(FILE, "%s: server %s handed out "
 225                                "a duplicate delegation!\n",
 226                                __func__, clp->cl_hostname);
 227                if (delegation->type <= nfsi->delegation->type) {
 228                        freeme = delegation;
 229                        delegation = NULL;
 230                        goto out;
 231                }
 232                freeme = nfs_detach_delegation_locked(nfsi, NULL);
 233        }
 234        list_add_rcu(&delegation->super_list, &clp->cl_delegations);
 235        nfsi->delegation_state = delegation->type;
 236        rcu_assign_pointer(nfsi->delegation, delegation);
 237        delegation = NULL;
 238
 239        /* Ensure we revalidate the attributes and page cache! */
 240        spin_lock(&inode->i_lock);
 241        nfsi->cache_validity |= NFS_INO_REVAL_FORCED;
 242        spin_unlock(&inode->i_lock);
 243
 244out:
 245        spin_unlock(&clp->cl_lock);
 246        if (delegation != NULL)
 247                nfs_free_delegation(delegation);
 248        if (freeme != NULL)
 249                nfs_do_return_delegation(inode, freeme, 0);
 250        return status;
 251}
 252
 253/* Sync all data to disk upon delegation return */
 254static void nfs_msync_inode(struct inode *inode)
 255{
 256        filemap_fdatawrite(inode->i_mapping);
 257        nfs_wb_all(inode);
 258        filemap_fdatawait(inode->i_mapping);
 259}
 260
 261/*
 262 * Basic procedure for returning a delegation to the server
 263 */
 264static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation)
 265{
 266        struct nfs_inode *nfsi = NFS_I(inode);
 267
 268        nfs_msync_inode(inode);
 269        /*
 270         * Guard against new delegated open/lock/unlock calls and against
 271         * state recovery
 272         */
 273        down_write(&nfsi->rwsem);
 274        nfs_delegation_claim_opens(inode, &delegation->stateid);
 275        up_write(&nfsi->rwsem);
 276        nfs_msync_inode(inode);
 277
 278        return nfs_do_return_delegation(inode, delegation, 1);
 279}
 280
 281/*
 282 * Return all delegations that have been marked for return
 283 */
 284void nfs_client_return_marked_delegations(struct nfs_client *clp)
 285{
 286        struct nfs_delegation *delegation;
 287        struct inode *inode;
 288
 289restart:
 290        rcu_read_lock();
 291        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
 292                if (!test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
 293                        continue;
 294                inode = nfs_delegation_grab_inode(delegation);
 295                if (inode == NULL)
 296                        continue;
 297                spin_lock(&clp->cl_lock);
 298                delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
 299                spin_unlock(&clp->cl_lock);
 300                rcu_read_unlock();
 301                if (delegation != NULL)
 302                        __nfs_inode_return_delegation(inode, delegation);
 303                iput(inode);
 304                goto restart;
 305        }
 306        rcu_read_unlock();
 307}
 308
 309/*
 310 * This function returns the delegation without reclaiming opens
 311 * or protecting against delegation reclaims.
 312 * It is therefore really only safe to be called from
 313 * nfs4_clear_inode()
 314 */
 315void nfs_inode_return_delegation_noreclaim(struct inode *inode)
 316{
 317        struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
 318        struct nfs_inode *nfsi = NFS_I(inode);
 319        struct nfs_delegation *delegation;
 320
 321        if (rcu_dereference(nfsi->delegation) != NULL) {
 322                spin_lock(&clp->cl_lock);
 323                delegation = nfs_detach_delegation_locked(nfsi, NULL);
 324                spin_unlock(&clp->cl_lock);
 325                if (delegation != NULL)
 326                        nfs_do_return_delegation(inode, delegation, 0);
 327        }
 328}
 329
 330int nfs_inode_return_delegation(struct inode *inode)
 331{
 332        struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
 333        struct nfs_inode *nfsi = NFS_I(inode);
 334        struct nfs_delegation *delegation;
 335        int err = 0;
 336
 337        if (rcu_dereference(nfsi->delegation) != NULL) {
 338                spin_lock(&clp->cl_lock);
 339                delegation = nfs_detach_delegation_locked(nfsi, NULL);
 340                spin_unlock(&clp->cl_lock);
 341                if (delegation != NULL)
 342                        err = __nfs_inode_return_delegation(inode, delegation);
 343        }
 344        return err;
 345}
 346
 347static void nfs_mark_return_delegation(struct nfs_client *clp, struct nfs_delegation *delegation)
 348{
 349        set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
 350        set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
 351}
 352
 353/*
 354 * Return all delegations associated to a super block
 355 */
 356void nfs_super_return_all_delegations(struct super_block *sb)
 357{
 358        struct nfs_client *clp = NFS_SB(sb)->nfs_client;
 359        struct nfs_delegation *delegation;
 360
 361        if (clp == NULL)
 362                return;
 363        rcu_read_lock();
 364        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
 365                spin_lock(&delegation->lock);
 366                if (delegation->inode != NULL && delegation->inode->i_sb == sb)
 367                        set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
 368                spin_unlock(&delegation->lock);
 369        }
 370        rcu_read_unlock();
 371        nfs_client_return_marked_delegations(clp);
 372}
 373
 374static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
 375{
 376        struct nfs_delegation *delegation;
 377
 378        rcu_read_lock();
 379        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
 380                set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
 381                set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
 382        }
 383        rcu_read_unlock();
 384}
 385
 386static void nfs_delegation_run_state_manager(struct nfs_client *clp)
 387{
 388        if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
 389                nfs4_schedule_state_manager(clp);
 390}
 391
 392void nfs_expire_all_delegations(struct nfs_client *clp)
 393{
 394        nfs_client_mark_return_all_delegations(clp);
 395        nfs_delegation_run_state_manager(clp);
 396}
 397
 398/*
 399 * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
 400 */
 401void nfs_handle_cb_pathdown(struct nfs_client *clp)
 402{
 403        if (clp == NULL)
 404                return;
 405        nfs_client_mark_return_all_delegations(clp);
 406}
 407
 408static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *clp)
 409{
 410        struct nfs_delegation *delegation;
 411
 412        rcu_read_lock();
 413        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
 414                if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
 415                        continue;
 416                set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
 417                set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
 418        }
 419        rcu_read_unlock();
 420}
 421
 422void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
 423{
 424        nfs_client_mark_return_unreferenced_delegations(clp);
 425        nfs_delegation_run_state_manager(clp);
 426}
 427
 428/*
 429 * Asynchronous delegation recall!
 430 */
 431int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
 432{
 433        struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
 434        struct nfs_delegation *delegation;
 435
 436        rcu_read_lock();
 437        delegation = rcu_dereference(NFS_I(inode)->delegation);
 438        if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
 439                                sizeof(delegation->stateid.data)) != 0) {
 440                rcu_read_unlock();
 441                return -ENOENT;
 442        }
 443        nfs_mark_return_delegation(clp, delegation);
 444        rcu_read_unlock();
 445        nfs_delegation_run_state_manager(clp);
 446        return 0;
 447}
 448
 449/*
 450 * Retrieve the inode associated with a delegation
 451 */
 452struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle)
 453{
 454        struct nfs_delegation *delegation;
 455        struct inode *res = NULL;
 456        rcu_read_lock();
 457        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
 458                spin_lock(&delegation->lock);
 459                if (delegation->inode != NULL &&
 460                    nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
 461                        res = igrab(delegation->inode);
 462                }
 463                spin_unlock(&delegation->lock);
 464                if (res != NULL)
 465                        break;
 466        }
 467        rcu_read_unlock();
 468        return res;
 469}
 470
 471/*
 472 * Mark all delegations as needing to be reclaimed
 473 */
 474void nfs_delegation_mark_reclaim(struct nfs_client *clp)
 475{
 476        struct nfs_delegation *delegation;
 477        rcu_read_lock();
 478        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list)
 479                set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
 480        rcu_read_unlock();
 481}
 482
 483/*
 484 * Reap all unclaimed delegations after reboot recovery is done
 485 */
 486void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
 487{
 488        struct nfs_delegation *delegation;
 489        struct inode *inode;
 490restart:
 491        rcu_read_lock();
 492        list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
 493                if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0)
 494                        continue;
 495                inode = nfs_delegation_grab_inode(delegation);
 496                if (inode == NULL)
 497                        continue;
 498                spin_lock(&clp->cl_lock);
 499                delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
 500                spin_unlock(&clp->cl_lock);
 501                rcu_read_unlock();
 502                if (delegation != NULL)
 503                        nfs_free_delegation(delegation);
 504                iput(inode);
 505                goto restart;
 506        }
 507        rcu_read_unlock();
 508}
 509
 510int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
 511{
 512        struct nfs_inode *nfsi = NFS_I(inode);
 513        struct nfs_delegation *delegation;
 514        int ret = 0;
 515
 516        rcu_read_lock();
 517        delegation = rcu_dereference(nfsi->delegation);
 518        if (delegation != NULL) {
 519                memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
 520                ret = 1;
 521        }
 522        rcu_read_unlock();
 523        return ret;
 524}
 525