📄 nfs4state.c
字号:
spin_unlock(&inode->i_lock); if (new) nfs4_free_open_state(new); }out: return state;}/* * Beware! Caller must be holding exactly one * reference to clp->cl_sem and owner->so_sema! */void nfs4_put_open_state(struct nfs4_state *state){ struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) return; if (!list_empty(&state->inode_states)) list_del(&state->inode_states); spin_unlock(&inode->i_lock); list_del(&state->open_states); BUG_ON (state->state != 0); nfs4_free_open_state(state); nfs4_put_state_owner(owner);}/* * Beware! Caller must be holding no references to clp->cl_sem! * of owner->so_sema! */void nfs4_close_state(struct nfs4_state *state, mode_t mode){ struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; struct nfs4_client *clp = owner->so_client; int newstate; int status = 0; atomic_inc(&owner->so_count); down_read(&clp->cl_sem); down(&owner->so_sema); /* Protect against nfs4_find_state() */ spin_lock(&inode->i_lock); if (mode & FMODE_READ) state->nreaders--; if (mode & FMODE_WRITE) state->nwriters--; if (state->nwriters == 0 && state->nreaders == 0) list_del_init(&state->inode_states); spin_unlock(&inode->i_lock); newstate = 0; if (state->state != 0) { if (state->nreaders) newstate |= FMODE_READ; if (state->nwriters) newstate |= FMODE_WRITE; if (state->state == newstate) goto out; if (newstate != 0) status = nfs4_do_downgrade(inode, state, newstate); else status = nfs4_do_close(inode, state); }out: nfs4_put_open_state(state); up(&owner->so_sema); nfs4_put_state_owner(owner); up_read(&clp->cl_sem);}/* * Search the state->lock_states for an existing lock_owner * that is compatible with current->files */static struct nfs4_lock_state *__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner){ struct nfs4_lock_state *pos; list_for_each_entry(pos, &state->lock_states, ls_locks) { if (pos->ls_owner != fl_owner) continue; atomic_inc(&pos->ls_count); return pos; } return NULL;}struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner){ struct nfs4_lock_state *lsp; read_lock(&state->state_lock); lsp = __nfs4_find_lock_state(state, fl_owner); read_unlock(&state->state_lock); return lsp;}/* * Return a compatible lock_state. If no initialized lock_state structure * exists, return an uninitialized one. * * The caller must be holding state->lock_sema */static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner){ struct nfs4_lock_state *lsp; struct nfs4_client *clp = state->owner->so_client; lsp = kmalloc(sizeof(*lsp), GFP_KERNEL); if (lsp == NULL) return NULL; lsp->ls_flags = 0; lsp->ls_seqid = 0; /* arbitrary */ lsp->ls_id = -1; memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); atomic_set(&lsp->ls_count, 1); lsp->ls_owner = fl_owner; INIT_LIST_HEAD(&lsp->ls_locks); spin_lock(&clp->cl_lock); lsp->ls_id = nfs4_alloc_lockowner_id(clp); spin_unlock(&clp->cl_lock); return lsp;}/* * Return a compatible lock_state. If no initialized lock_state structure * exists, return an uninitialized one. * * The caller must be holding state->lock_sema and clp->cl_sem */struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner){ struct nfs4_lock_state * lsp; lsp = nfs4_find_lock_state(state, owner); if (lsp == NULL) lsp = nfs4_alloc_lock_state(state, owner); return lsp;}/* * Byte-range lock aware utility to initialize the stateid of read/write * requests. */voidnfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner){ if (test_bit(LK_STATE_IN_USE, &state->flags)) { struct nfs4_lock_state *lsp; lsp = nfs4_find_lock_state(state, fl_owner); if (lsp) { memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); nfs4_put_lock_state(lsp); return; } } memcpy(dst, &state->stateid, sizeof(*dst));}/** Called with state->lock_sema and clp->cl_sem held.*/void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp){ if (status == NFS_OK || seqid_mutating_err(-status)) lsp->ls_seqid++;}/* * Check to see if the request lock (type FL_UNLK) effects the fl lock.** fl and request must have the same posix owner** return: * 0 -> fl not effected by request* 1 -> fl consumed by request*/static intnfs4_check_unlock(struct file_lock *fl, struct file_lock *request){ if (fl->fl_start >= request->fl_start && fl->fl_end <= request->fl_end) return 1; return 0;}/* * Post an initialized lock_state on the state->lock_states list. */void nfs4_notify_setlk(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp){ if (!list_empty(&lsp->ls_locks)) return; atomic_inc(&lsp->ls_count); write_lock(&state->state_lock); list_add(&lsp->ls_locks, &state->lock_states); set_bit(LK_STATE_IN_USE, &state->flags); write_unlock(&state->state_lock);}/* * to decide to 'reap' lock state: * 1) search i_flock for file_locks with fl.lock_state = to ls. * 2) determine if unlock will consume found lock. * if so, reap * * else, don't reap. * */voidnfs4_notify_unlck(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp){ struct inode *inode = state->inode; struct file_lock *fl; for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & FL_POSIX)) continue; if (fl->fl_owner != lsp->ls_owner) continue; /* Exit if we find at least one lock which is not consumed */ if (nfs4_check_unlock(fl,request) == 0) return; } write_lock(&state->state_lock); list_del_init(&lsp->ls_locks); if (list_empty(&state->lock_states)) clear_bit(LK_STATE_IN_USE, &state->flags); write_unlock(&state->state_lock); nfs4_put_lock_state(lsp);}/* * Release reference to lock_state, and free it if we see that * it is no longer in use */voidnfs4_put_lock_state(struct nfs4_lock_state *lsp){ if (!atomic_dec_and_test(&lsp->ls_count)) return; BUG_ON (!list_empty(&lsp->ls_locks)); kfree(lsp);}/** Called with sp->so_sema and clp->cl_sem held.** Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or* failed with a seqid incrementing error -* see comments nfs_fs.h:seqid_mutating_error()*/void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp){ if (status == NFS_OK || seqid_mutating_err(-status)) sp->so_seqid++; /* If the server returns BAD_SEQID, unhash state_owner here */ if (status == -NFS4ERR_BAD_SEQID) nfs4_unhash_state_owner(sp);}static int reclaimer(void *);struct reclaimer_args { struct nfs4_client *clp; struct completion complete;};/* * State recovery routine */voidnfs4_recover_state(void *data){ struct nfs4_client *clp = (struct nfs4_client *)data; struct reclaimer_args args = { .clp = clp, }; might_sleep(); init_completion(&args.complete); if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0) goto out_failed_clear; wait_for_completion(&args.complete); return;out_failed_clear: set_bit(NFS4CLNT_OK, &clp->cl_state); wake_up_all(&clp->cl_waitq); rpc_wake_up(&clp->cl_rpcwaitq);}/* * Schedule a state recovery attempt */voidnfs4_schedule_state_recovery(struct nfs4_client *clp){ if (!clp) return; if (test_and_clear_bit(NFS4CLNT_OK, &clp->cl_state)) schedule_work(&clp->cl_recoverd);}static int nfs4_reclaim_locks(struct nfs4_state *state){ struct inode *inode = state->inode; struct file_lock *fl; int status = 0; for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) { if (!(fl->fl_flags & FL_POSIX)) continue; if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state) continue; status = nfs4_lock_reclaim(state, fl); if (status >= 0) continue; switch (status) { default: printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", __FUNCTION__, status); case -NFS4ERR_EXPIRED: case -NFS4ERR_NO_GRACE: case -NFS4ERR_RECLAIM_BAD: case -NFS4ERR_RECLAIM_CONFLICT: /* kill_proc(fl->fl_owner, SIGLOST, 1); */ break; case -NFS4ERR_STALE_CLIENTID: goto out_err; } } return 0;out_err: return status;}static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp){ struct nfs4_state *state; struct nfs4_lock_state *lock; int status = 0; list_for_each_entry(state, &sp->so_states, open_states) { if (state->state == 0) continue; status = nfs4_open_reclaim(sp, state); list_for_each_entry(lock, &state->lock_states, ls_locks) lock->ls_flags &= ~NFS_LOCK_INITIALIZED; if (status >= 0) { status = nfs4_reclaim_locks(state); if (status < 0) goto out_err; list_for_each_entry(lock, &state->lock_states, ls_locks) { if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) printk("%s: Lock reclaim failed!\n", __FUNCTION__); } continue; } switch (status) { default: printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", __FUNCTION__, status); case -NFS4ERR_EXPIRED: case -NFS4ERR_NO_GRACE: case -NFS4ERR_RECLAIM_BAD: case -NFS4ERR_RECLAIM_CONFLICT: /* * Open state on this file cannot be recovered * All we can do is revert to using the zero stateid. */ memset(state->stateid.data, 0, sizeof(state->stateid.data)); /* Mark the file as being 'closed' */ state->state = 0; break; case -NFS4ERR_STALE_CLIENTID: goto out_err; } } return 0;out_err: return status;}static int reclaimer(void *ptr){ struct reclaimer_args *args = (struct reclaimer_args *)ptr; struct nfs4_client *clp = args->clp; struct nfs4_state_owner *sp; int status = 0; daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr)); allow_signal(SIGKILL); atomic_inc(&clp->cl_count); complete(&args->complete); /* Ensure exclusive access to NFSv4 state */ lock_kernel(); down_write(&clp->cl_sem); /* Are there any NFS mounts out there? */ if (list_empty(&clp->cl_superblocks)) goto out;restart_loop: status = nfs4_proc_renew(clp); if (status == 0 || status == -NFS4ERR_CB_PATH_DOWN) goto out; status = nfs4_init_client(clp); if (status) goto out_error; /* Mark all delagations for reclaim */ nfs_delegation_mark_reclaim(clp); /* Note: list is protected by exclusive lock on cl->cl_sem */ list_for_each_entry(sp, &clp->cl_state_owners, so_list) { status = nfs4_reclaim_open_state(sp); if (status < 0) { if (status == -NFS4ERR_STALE_CLIENTID) goto restart_loop; goto out_error; } } nfs_delegation_reap_unclaimed(clp);out: set_bit(NFS4CLNT_OK, &clp->cl_state); up_write(&clp->cl_sem); unlock_kernel(); wake_up_all(&clp->cl_waitq); rpc_wake_up(&clp->cl_rpcwaitq); if (status == -NFS4ERR_CB_PATH_DOWN) nfs_handle_cb_pathdown(clp); nfs4_put_client(clp); return 0;out_error: printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", NIPQUAD(clp->cl_addr.s_addr), -status); goto out;}/* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -