162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014 Christoph Hellwig. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/blkdev.h> 662306a36Sopenharmony_ci#include <linux/kmod.h> 762306a36Sopenharmony_ci#include <linux/file.h> 862306a36Sopenharmony_ci#include <linux/jhash.h> 962306a36Sopenharmony_ci#include <linux/sched.h> 1062306a36Sopenharmony_ci#include <linux/sunrpc/addr.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "pnfs.h" 1362306a36Sopenharmony_ci#include "netns.h" 1462306a36Sopenharmony_ci#include "trace.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define NFSDDBG_FACILITY NFSDDBG_PNFS 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct nfs4_layout { 1962306a36Sopenharmony_ci struct list_head lo_perstate; 2062306a36Sopenharmony_ci struct nfs4_layout_stateid *lo_state; 2162306a36Sopenharmony_ci struct nfsd4_layout_seg lo_seg; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic struct kmem_cache *nfs4_layout_cache; 2562306a36Sopenharmony_cistatic struct kmem_cache *nfs4_layout_stateid_cache; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const struct nfsd4_callback_ops nfsd4_cb_layout_ops; 2862306a36Sopenharmony_cistatic const struct lock_manager_operations nfsd4_layouts_lm_ops; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciconst struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = { 3162306a36Sopenharmony_ci#ifdef CONFIG_NFSD_FLEXFILELAYOUT 3262306a36Sopenharmony_ci [LAYOUT_FLEX_FILES] = &ff_layout_ops, 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci#ifdef CONFIG_NFSD_BLOCKLAYOUT 3562306a36Sopenharmony_ci [LAYOUT_BLOCK_VOLUME] = &bl_layout_ops, 3662306a36Sopenharmony_ci#endif 3762306a36Sopenharmony_ci#ifdef CONFIG_NFSD_SCSILAYOUT 3862306a36Sopenharmony_ci [LAYOUT_SCSI] = &scsi_layout_ops, 3962306a36Sopenharmony_ci#endif 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* pNFS device ID to export fsid mapping */ 4362306a36Sopenharmony_ci#define DEVID_HASH_BITS 8 4462306a36Sopenharmony_ci#define DEVID_HASH_SIZE (1 << DEVID_HASH_BITS) 4562306a36Sopenharmony_ci#define DEVID_HASH_MASK (DEVID_HASH_SIZE - 1) 4662306a36Sopenharmony_cistatic u64 nfsd_devid_seq = 1; 4762306a36Sopenharmony_cistatic struct list_head nfsd_devid_hash[DEVID_HASH_SIZE]; 4862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(nfsd_devid_lock); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic inline u32 devid_hashfn(u64 idx) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return jhash_2words(idx, idx >> 32, 0) & DEVID_HASH_MASK; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void 5662306a36Sopenharmony_cinfsd4_alloc_devid_map(const struct svc_fh *fhp) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci const struct knfsd_fh *fh = &fhp->fh_handle; 5962306a36Sopenharmony_ci size_t fsid_len = key_len(fh->fh_fsid_type); 6062306a36Sopenharmony_ci struct nfsd4_deviceid_map *map, *old; 6162306a36Sopenharmony_ci int i; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci map = kzalloc(sizeof(*map) + fsid_len, GFP_KERNEL); 6462306a36Sopenharmony_ci if (!map) 6562306a36Sopenharmony_ci return; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci map->fsid_type = fh->fh_fsid_type; 6862306a36Sopenharmony_ci memcpy(&map->fsid, fh->fh_fsid, fsid_len); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci spin_lock(&nfsd_devid_lock); 7162306a36Sopenharmony_ci if (fhp->fh_export->ex_devid_map) 7262306a36Sopenharmony_ci goto out_unlock; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < DEVID_HASH_SIZE; i++) { 7562306a36Sopenharmony_ci list_for_each_entry(old, &nfsd_devid_hash[i], hash) { 7662306a36Sopenharmony_ci if (old->fsid_type != fh->fh_fsid_type) 7762306a36Sopenharmony_ci continue; 7862306a36Sopenharmony_ci if (memcmp(old->fsid, fh->fh_fsid, 7962306a36Sopenharmony_ci key_len(old->fsid_type))) 8062306a36Sopenharmony_ci continue; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci fhp->fh_export->ex_devid_map = old; 8362306a36Sopenharmony_ci goto out_unlock; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci map->idx = nfsd_devid_seq++; 8862306a36Sopenharmony_ci list_add_tail_rcu(&map->hash, &nfsd_devid_hash[devid_hashfn(map->idx)]); 8962306a36Sopenharmony_ci fhp->fh_export->ex_devid_map = map; 9062306a36Sopenharmony_ci map = NULL; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciout_unlock: 9362306a36Sopenharmony_ci spin_unlock(&nfsd_devid_lock); 9462306a36Sopenharmony_ci kfree(map); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistruct nfsd4_deviceid_map * 9862306a36Sopenharmony_cinfsd4_find_devid_map(int idx) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct nfsd4_deviceid_map *map, *ret = NULL; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci rcu_read_lock(); 10362306a36Sopenharmony_ci list_for_each_entry_rcu(map, &nfsd_devid_hash[devid_hashfn(idx)], hash) 10462306a36Sopenharmony_ci if (map->idx == idx) 10562306a36Sopenharmony_ci ret = map; 10662306a36Sopenharmony_ci rcu_read_unlock(); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return ret; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciint 11262306a36Sopenharmony_cinfsd4_set_deviceid(struct nfsd4_deviceid *id, const struct svc_fh *fhp, 11362306a36Sopenharmony_ci u32 device_generation) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci if (!fhp->fh_export->ex_devid_map) { 11662306a36Sopenharmony_ci nfsd4_alloc_devid_map(fhp); 11762306a36Sopenharmony_ci if (!fhp->fh_export->ex_devid_map) 11862306a36Sopenharmony_ci return -ENOMEM; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci id->fsid_idx = fhp->fh_export->ex_devid_map->idx; 12262306a36Sopenharmony_ci id->generation = device_generation; 12362306a36Sopenharmony_ci id->pad = 0; 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_civoid nfsd4_setup_layout_type(struct svc_export *exp) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci#if defined(CONFIG_NFSD_BLOCKLAYOUT) || defined(CONFIG_NFSD_SCSILAYOUT) 13062306a36Sopenharmony_ci struct super_block *sb = exp->ex_path.mnt->mnt_sb; 13162306a36Sopenharmony_ci#endif 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (!(exp->ex_flags & NFSEXP_PNFS)) 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#ifdef CONFIG_NFSD_FLEXFILELAYOUT 13762306a36Sopenharmony_ci exp->ex_layout_types |= 1 << LAYOUT_FLEX_FILES; 13862306a36Sopenharmony_ci#endif 13962306a36Sopenharmony_ci#ifdef CONFIG_NFSD_BLOCKLAYOUT 14062306a36Sopenharmony_ci if (sb->s_export_op->get_uuid && 14162306a36Sopenharmony_ci sb->s_export_op->map_blocks && 14262306a36Sopenharmony_ci sb->s_export_op->commit_blocks) 14362306a36Sopenharmony_ci exp->ex_layout_types |= 1 << LAYOUT_BLOCK_VOLUME; 14462306a36Sopenharmony_ci#endif 14562306a36Sopenharmony_ci#ifdef CONFIG_NFSD_SCSILAYOUT 14662306a36Sopenharmony_ci if (sb->s_export_op->map_blocks && 14762306a36Sopenharmony_ci sb->s_export_op->commit_blocks && 14862306a36Sopenharmony_ci sb->s_bdev && 14962306a36Sopenharmony_ci sb->s_bdev->bd_disk->fops->pr_ops && 15062306a36Sopenharmony_ci sb->s_bdev->bd_disk->fops->get_unique_id) 15162306a36Sopenharmony_ci exp->ex_layout_types |= 1 << LAYOUT_SCSI; 15262306a36Sopenharmony_ci#endif 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void 15662306a36Sopenharmony_cinfsd4_free_layout_stateid(struct nfs4_stid *stid) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct nfs4_layout_stateid *ls = layoutstateid(stid); 15962306a36Sopenharmony_ci struct nfs4_client *clp = ls->ls_stid.sc_client; 16062306a36Sopenharmony_ci struct nfs4_file *fp = ls->ls_stid.sc_file; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci trace_nfsd_layoutstate_free(&ls->ls_stid.sc_stateid); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci spin_lock(&clp->cl_lock); 16562306a36Sopenharmony_ci list_del_init(&ls->ls_perclnt); 16662306a36Sopenharmony_ci spin_unlock(&clp->cl_lock); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci spin_lock(&fp->fi_lock); 16962306a36Sopenharmony_ci list_del_init(&ls->ls_perfile); 17062306a36Sopenharmony_ci spin_unlock(&fp->fi_lock); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!nfsd4_layout_ops[ls->ls_layout_type]->disable_recalls) 17362306a36Sopenharmony_ci vfs_setlease(ls->ls_file->nf_file, F_UNLCK, NULL, (void **)&ls); 17462306a36Sopenharmony_ci nfsd_file_put(ls->ls_file); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (ls->ls_recalled) 17762306a36Sopenharmony_ci atomic_dec(&ls->ls_stid.sc_file->fi_lo_recalls); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci kmem_cache_free(nfs4_layout_stateid_cache, ls); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int 18362306a36Sopenharmony_cinfsd4_layout_setlease(struct nfs4_layout_stateid *ls) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct file_lock *fl; 18662306a36Sopenharmony_ci int status; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (nfsd4_layout_ops[ls->ls_layout_type]->disable_recalls) 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci fl = locks_alloc_lock(); 19262306a36Sopenharmony_ci if (!fl) 19362306a36Sopenharmony_ci return -ENOMEM; 19462306a36Sopenharmony_ci locks_init_lock(fl); 19562306a36Sopenharmony_ci fl->fl_lmops = &nfsd4_layouts_lm_ops; 19662306a36Sopenharmony_ci fl->fl_flags = FL_LAYOUT; 19762306a36Sopenharmony_ci fl->fl_type = F_RDLCK; 19862306a36Sopenharmony_ci fl->fl_end = OFFSET_MAX; 19962306a36Sopenharmony_ci fl->fl_owner = ls; 20062306a36Sopenharmony_ci fl->fl_pid = current->tgid; 20162306a36Sopenharmony_ci fl->fl_file = ls->ls_file->nf_file; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci status = vfs_setlease(fl->fl_file, fl->fl_type, &fl, NULL); 20462306a36Sopenharmony_ci if (status) { 20562306a36Sopenharmony_ci locks_free_lock(fl); 20662306a36Sopenharmony_ci return status; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci BUG_ON(fl != NULL); 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic struct nfs4_layout_stateid * 21362306a36Sopenharmony_cinfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, 21462306a36Sopenharmony_ci struct nfs4_stid *parent, u32 layout_type) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct nfs4_client *clp = cstate->clp; 21762306a36Sopenharmony_ci struct nfs4_file *fp = parent->sc_file; 21862306a36Sopenharmony_ci struct nfs4_layout_stateid *ls; 21962306a36Sopenharmony_ci struct nfs4_stid *stp; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache, 22262306a36Sopenharmony_ci nfsd4_free_layout_stateid); 22362306a36Sopenharmony_ci if (!stp) 22462306a36Sopenharmony_ci return NULL; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci get_nfs4_file(fp); 22762306a36Sopenharmony_ci stp->sc_file = fp; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ls = layoutstateid(stp); 23062306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_perclnt); 23162306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_perfile); 23262306a36Sopenharmony_ci spin_lock_init(&ls->ls_lock); 23362306a36Sopenharmony_ci INIT_LIST_HEAD(&ls->ls_layouts); 23462306a36Sopenharmony_ci mutex_init(&ls->ls_mutex); 23562306a36Sopenharmony_ci ls->ls_layout_type = layout_type; 23662306a36Sopenharmony_ci nfsd4_init_cb(&ls->ls_recall, clp, &nfsd4_cb_layout_ops, 23762306a36Sopenharmony_ci NFSPROC4_CLNT_CB_LAYOUT); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (parent->sc_type == NFS4_DELEG_STID) 24062306a36Sopenharmony_ci ls->ls_file = nfsd_file_get(fp->fi_deleg_file); 24162306a36Sopenharmony_ci else 24262306a36Sopenharmony_ci ls->ls_file = find_any_file(fp); 24362306a36Sopenharmony_ci BUG_ON(!ls->ls_file); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (nfsd4_layout_setlease(ls)) { 24662306a36Sopenharmony_ci nfsd_file_put(ls->ls_file); 24762306a36Sopenharmony_ci put_nfs4_file(fp); 24862306a36Sopenharmony_ci kmem_cache_free(nfs4_layout_stateid_cache, ls); 24962306a36Sopenharmony_ci return NULL; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci spin_lock(&clp->cl_lock); 25362306a36Sopenharmony_ci stp->sc_type = NFS4_LAYOUT_STID; 25462306a36Sopenharmony_ci list_add(&ls->ls_perclnt, &clp->cl_lo_states); 25562306a36Sopenharmony_ci spin_unlock(&clp->cl_lock); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci spin_lock(&fp->fi_lock); 25862306a36Sopenharmony_ci list_add(&ls->ls_perfile, &fp->fi_lo_states); 25962306a36Sopenharmony_ci spin_unlock(&fp->fi_lock); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci trace_nfsd_layoutstate_alloc(&ls->ls_stid.sc_stateid); 26262306a36Sopenharmony_ci return ls; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci__be32 26662306a36Sopenharmony_cinfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp, 26762306a36Sopenharmony_ci struct nfsd4_compound_state *cstate, stateid_t *stateid, 26862306a36Sopenharmony_ci bool create, u32 layout_type, struct nfs4_layout_stateid **lsp) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct nfs4_layout_stateid *ls; 27162306a36Sopenharmony_ci struct nfs4_stid *stid; 27262306a36Sopenharmony_ci unsigned char typemask = NFS4_LAYOUT_STID; 27362306a36Sopenharmony_ci __be32 status; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (create) 27662306a36Sopenharmony_ci typemask |= (NFS4_OPEN_STID | NFS4_LOCK_STID | NFS4_DELEG_STID); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci status = nfsd4_lookup_stateid(cstate, stateid, typemask, &stid, 27962306a36Sopenharmony_ci net_generic(SVC_NET(rqstp), nfsd_net_id)); 28062306a36Sopenharmony_ci if (status) 28162306a36Sopenharmony_ci goto out; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (!fh_match(&cstate->current_fh.fh_handle, 28462306a36Sopenharmony_ci &stid->sc_file->fi_fhandle)) { 28562306a36Sopenharmony_ci status = nfserr_bad_stateid; 28662306a36Sopenharmony_ci goto out_put_stid; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (stid->sc_type != NFS4_LAYOUT_STID) { 29062306a36Sopenharmony_ci ls = nfsd4_alloc_layout_stateid(cstate, stid, layout_type); 29162306a36Sopenharmony_ci nfs4_put_stid(stid); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci status = nfserr_jukebox; 29462306a36Sopenharmony_ci if (!ls) 29562306a36Sopenharmony_ci goto out; 29662306a36Sopenharmony_ci mutex_lock(&ls->ls_mutex); 29762306a36Sopenharmony_ci } else { 29862306a36Sopenharmony_ci ls = container_of(stid, struct nfs4_layout_stateid, ls_stid); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci status = nfserr_bad_stateid; 30162306a36Sopenharmony_ci mutex_lock(&ls->ls_mutex); 30262306a36Sopenharmony_ci if (nfsd4_stateid_generation_after(stateid, &stid->sc_stateid)) 30362306a36Sopenharmony_ci goto out_unlock_stid; 30462306a36Sopenharmony_ci if (layout_type != ls->ls_layout_type) 30562306a36Sopenharmony_ci goto out_unlock_stid; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci *lsp = ls; 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ciout_unlock_stid: 31262306a36Sopenharmony_ci mutex_unlock(&ls->ls_mutex); 31362306a36Sopenharmony_ciout_put_stid: 31462306a36Sopenharmony_ci nfs4_put_stid(stid); 31562306a36Sopenharmony_ciout: 31662306a36Sopenharmony_ci return status; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic void 32062306a36Sopenharmony_cinfsd4_recall_file_layout(struct nfs4_layout_stateid *ls) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci spin_lock(&ls->ls_lock); 32362306a36Sopenharmony_ci if (ls->ls_recalled) 32462306a36Sopenharmony_ci goto out_unlock; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (list_empty(&ls->ls_layouts)) 32762306a36Sopenharmony_ci goto out_unlock; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ls->ls_recalled = true; 33062306a36Sopenharmony_ci atomic_inc(&ls->ls_stid.sc_file->fi_lo_recalls); 33162306a36Sopenharmony_ci trace_nfsd_layout_recall(&ls->ls_stid.sc_stateid); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci refcount_inc(&ls->ls_stid.sc_count); 33462306a36Sopenharmony_ci nfsd4_run_cb(&ls->ls_recall); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ciout_unlock: 33762306a36Sopenharmony_ci spin_unlock(&ls->ls_lock); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic inline u64 34162306a36Sopenharmony_cilayout_end(struct nfsd4_layout_seg *seg) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci u64 end = seg->offset + seg->length; 34462306a36Sopenharmony_ci return end >= seg->offset ? end : NFS4_MAX_UINT64; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void 34862306a36Sopenharmony_cilayout_update_len(struct nfsd4_layout_seg *lo, u64 end) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci if (end == NFS4_MAX_UINT64) 35162306a36Sopenharmony_ci lo->length = NFS4_MAX_UINT64; 35262306a36Sopenharmony_ci else 35362306a36Sopenharmony_ci lo->length = end - lo->offset; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic bool 35762306a36Sopenharmony_cilayouts_overlapping(struct nfs4_layout *lo, struct nfsd4_layout_seg *s) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci if (s->iomode != IOMODE_ANY && s->iomode != lo->lo_seg.iomode) 36062306a36Sopenharmony_ci return false; 36162306a36Sopenharmony_ci if (layout_end(&lo->lo_seg) <= s->offset) 36262306a36Sopenharmony_ci return false; 36362306a36Sopenharmony_ci if (layout_end(s) <= lo->lo_seg.offset) 36462306a36Sopenharmony_ci return false; 36562306a36Sopenharmony_ci return true; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic bool 36962306a36Sopenharmony_cilayouts_try_merge(struct nfsd4_layout_seg *lo, struct nfsd4_layout_seg *new) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci if (lo->iomode != new->iomode) 37262306a36Sopenharmony_ci return false; 37362306a36Sopenharmony_ci if (layout_end(new) < lo->offset) 37462306a36Sopenharmony_ci return false; 37562306a36Sopenharmony_ci if (layout_end(lo) < new->offset) 37662306a36Sopenharmony_ci return false; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci lo->offset = min(lo->offset, new->offset); 37962306a36Sopenharmony_ci layout_update_len(lo, max(layout_end(lo), layout_end(new))); 38062306a36Sopenharmony_ci return true; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic __be32 38462306a36Sopenharmony_cinfsd4_recall_conflict(struct nfs4_layout_stateid *ls) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct nfs4_file *fp = ls->ls_stid.sc_file; 38762306a36Sopenharmony_ci struct nfs4_layout_stateid *l, *n; 38862306a36Sopenharmony_ci __be32 nfserr = nfs_ok; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci assert_spin_locked(&fp->fi_lock); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci list_for_each_entry_safe(l, n, &fp->fi_lo_states, ls_perfile) { 39362306a36Sopenharmony_ci if (l != ls) { 39462306a36Sopenharmony_ci nfsd4_recall_file_layout(l); 39562306a36Sopenharmony_ci nfserr = nfserr_recallconflict; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return nfserr; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci__be32 40362306a36Sopenharmony_cinfsd4_insert_layout(struct nfsd4_layoutget *lgp, struct nfs4_layout_stateid *ls) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct nfsd4_layout_seg *seg = &lgp->lg_seg; 40662306a36Sopenharmony_ci struct nfs4_file *fp = ls->ls_stid.sc_file; 40762306a36Sopenharmony_ci struct nfs4_layout *lp, *new = NULL; 40862306a36Sopenharmony_ci __be32 nfserr; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci spin_lock(&fp->fi_lock); 41162306a36Sopenharmony_ci nfserr = nfsd4_recall_conflict(ls); 41262306a36Sopenharmony_ci if (nfserr) 41362306a36Sopenharmony_ci goto out; 41462306a36Sopenharmony_ci spin_lock(&ls->ls_lock); 41562306a36Sopenharmony_ci list_for_each_entry(lp, &ls->ls_layouts, lo_perstate) { 41662306a36Sopenharmony_ci if (layouts_try_merge(&lp->lo_seg, seg)) 41762306a36Sopenharmony_ci goto done; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci spin_unlock(&ls->ls_lock); 42062306a36Sopenharmony_ci spin_unlock(&fp->fi_lock); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci new = kmem_cache_alloc(nfs4_layout_cache, GFP_KERNEL); 42362306a36Sopenharmony_ci if (!new) 42462306a36Sopenharmony_ci return nfserr_jukebox; 42562306a36Sopenharmony_ci memcpy(&new->lo_seg, seg, sizeof(new->lo_seg)); 42662306a36Sopenharmony_ci new->lo_state = ls; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci spin_lock(&fp->fi_lock); 42962306a36Sopenharmony_ci nfserr = nfsd4_recall_conflict(ls); 43062306a36Sopenharmony_ci if (nfserr) 43162306a36Sopenharmony_ci goto out; 43262306a36Sopenharmony_ci spin_lock(&ls->ls_lock); 43362306a36Sopenharmony_ci list_for_each_entry(lp, &ls->ls_layouts, lo_perstate) { 43462306a36Sopenharmony_ci if (layouts_try_merge(&lp->lo_seg, seg)) 43562306a36Sopenharmony_ci goto done; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci refcount_inc(&ls->ls_stid.sc_count); 43962306a36Sopenharmony_ci list_add_tail(&new->lo_perstate, &ls->ls_layouts); 44062306a36Sopenharmony_ci new = NULL; 44162306a36Sopenharmony_cidone: 44262306a36Sopenharmony_ci nfs4_inc_and_copy_stateid(&lgp->lg_sid, &ls->ls_stid); 44362306a36Sopenharmony_ci spin_unlock(&ls->ls_lock); 44462306a36Sopenharmony_ciout: 44562306a36Sopenharmony_ci spin_unlock(&fp->fi_lock); 44662306a36Sopenharmony_ci if (new) 44762306a36Sopenharmony_ci kmem_cache_free(nfs4_layout_cache, new); 44862306a36Sopenharmony_ci return nfserr; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void 45262306a36Sopenharmony_cinfsd4_free_layouts(struct list_head *reaplist) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci while (!list_empty(reaplist)) { 45562306a36Sopenharmony_ci struct nfs4_layout *lp = list_first_entry(reaplist, 45662306a36Sopenharmony_ci struct nfs4_layout, lo_perstate); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci list_del(&lp->lo_perstate); 45962306a36Sopenharmony_ci nfs4_put_stid(&lp->lo_state->ls_stid); 46062306a36Sopenharmony_ci kmem_cache_free(nfs4_layout_cache, lp); 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic void 46562306a36Sopenharmony_cinfsd4_return_file_layout(struct nfs4_layout *lp, struct nfsd4_layout_seg *seg, 46662306a36Sopenharmony_ci struct list_head *reaplist) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct nfsd4_layout_seg *lo = &lp->lo_seg; 46962306a36Sopenharmony_ci u64 end = layout_end(lo); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (seg->offset <= lo->offset) { 47262306a36Sopenharmony_ci if (layout_end(seg) >= end) { 47362306a36Sopenharmony_ci list_move_tail(&lp->lo_perstate, reaplist); 47462306a36Sopenharmony_ci return; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci lo->offset = layout_end(seg); 47762306a36Sopenharmony_ci } else { 47862306a36Sopenharmony_ci /* retain the whole layout segment on a split. */ 47962306a36Sopenharmony_ci if (layout_end(seg) < end) { 48062306a36Sopenharmony_ci dprintk("%s: split not supported\n", __func__); 48162306a36Sopenharmony_ci return; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci end = seg->offset; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci layout_update_len(lo, end); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci__be32 49062306a36Sopenharmony_cinfsd4_return_file_layouts(struct svc_rqst *rqstp, 49162306a36Sopenharmony_ci struct nfsd4_compound_state *cstate, 49262306a36Sopenharmony_ci struct nfsd4_layoutreturn *lrp) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci struct nfs4_layout_stateid *ls; 49562306a36Sopenharmony_ci struct nfs4_layout *lp, *n; 49662306a36Sopenharmony_ci LIST_HEAD(reaplist); 49762306a36Sopenharmony_ci __be32 nfserr; 49862306a36Sopenharmony_ci int found = 0; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lrp->lr_sid, 50162306a36Sopenharmony_ci false, lrp->lr_layout_type, 50262306a36Sopenharmony_ci &ls); 50362306a36Sopenharmony_ci if (nfserr) { 50462306a36Sopenharmony_ci trace_nfsd_layout_return_lookup_fail(&lrp->lr_sid); 50562306a36Sopenharmony_ci return nfserr; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci spin_lock(&ls->ls_lock); 50962306a36Sopenharmony_ci list_for_each_entry_safe(lp, n, &ls->ls_layouts, lo_perstate) { 51062306a36Sopenharmony_ci if (layouts_overlapping(lp, &lrp->lr_seg)) { 51162306a36Sopenharmony_ci nfsd4_return_file_layout(lp, &lrp->lr_seg, &reaplist); 51262306a36Sopenharmony_ci found++; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci if (!list_empty(&ls->ls_layouts)) { 51662306a36Sopenharmony_ci if (found) 51762306a36Sopenharmony_ci nfs4_inc_and_copy_stateid(&lrp->lr_sid, &ls->ls_stid); 51862306a36Sopenharmony_ci lrp->lrs_present = 1; 51962306a36Sopenharmony_ci } else { 52062306a36Sopenharmony_ci trace_nfsd_layoutstate_unhash(&ls->ls_stid.sc_stateid); 52162306a36Sopenharmony_ci nfs4_unhash_stid(&ls->ls_stid); 52262306a36Sopenharmony_ci lrp->lrs_present = 0; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci spin_unlock(&ls->ls_lock); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci mutex_unlock(&ls->ls_mutex); 52762306a36Sopenharmony_ci nfs4_put_stid(&ls->ls_stid); 52862306a36Sopenharmony_ci nfsd4_free_layouts(&reaplist); 52962306a36Sopenharmony_ci return nfs_ok; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci__be32 53362306a36Sopenharmony_cinfsd4_return_client_layouts(struct svc_rqst *rqstp, 53462306a36Sopenharmony_ci struct nfsd4_compound_state *cstate, 53562306a36Sopenharmony_ci struct nfsd4_layoutreturn *lrp) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci struct nfs4_layout_stateid *ls, *n; 53862306a36Sopenharmony_ci struct nfs4_client *clp = cstate->clp; 53962306a36Sopenharmony_ci struct nfs4_layout *lp, *t; 54062306a36Sopenharmony_ci LIST_HEAD(reaplist); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci lrp->lrs_present = 0; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci spin_lock(&clp->cl_lock); 54562306a36Sopenharmony_ci list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) { 54662306a36Sopenharmony_ci if (ls->ls_layout_type != lrp->lr_layout_type) 54762306a36Sopenharmony_ci continue; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (lrp->lr_return_type == RETURN_FSID && 55062306a36Sopenharmony_ci !fh_fsid_match(&ls->ls_stid.sc_file->fi_fhandle, 55162306a36Sopenharmony_ci &cstate->current_fh.fh_handle)) 55262306a36Sopenharmony_ci continue; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci spin_lock(&ls->ls_lock); 55562306a36Sopenharmony_ci list_for_each_entry_safe(lp, t, &ls->ls_layouts, lo_perstate) { 55662306a36Sopenharmony_ci if (lrp->lr_seg.iomode == IOMODE_ANY || 55762306a36Sopenharmony_ci lrp->lr_seg.iomode == lp->lo_seg.iomode) 55862306a36Sopenharmony_ci list_move_tail(&lp->lo_perstate, &reaplist); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci spin_unlock(&ls->ls_lock); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci spin_unlock(&clp->cl_lock); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci nfsd4_free_layouts(&reaplist); 56562306a36Sopenharmony_ci return 0; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic void 56962306a36Sopenharmony_cinfsd4_return_all_layouts(struct nfs4_layout_stateid *ls, 57062306a36Sopenharmony_ci struct list_head *reaplist) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci spin_lock(&ls->ls_lock); 57362306a36Sopenharmony_ci list_splice_init(&ls->ls_layouts, reaplist); 57462306a36Sopenharmony_ci spin_unlock(&ls->ls_lock); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_civoid 57862306a36Sopenharmony_cinfsd4_return_all_client_layouts(struct nfs4_client *clp) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct nfs4_layout_stateid *ls, *n; 58162306a36Sopenharmony_ci LIST_HEAD(reaplist); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci spin_lock(&clp->cl_lock); 58462306a36Sopenharmony_ci list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) 58562306a36Sopenharmony_ci nfsd4_return_all_layouts(ls, &reaplist); 58662306a36Sopenharmony_ci spin_unlock(&clp->cl_lock); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci nfsd4_free_layouts(&reaplist); 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_civoid 59262306a36Sopenharmony_cinfsd4_return_all_file_layouts(struct nfs4_client *clp, struct nfs4_file *fp) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct nfs4_layout_stateid *ls, *n; 59562306a36Sopenharmony_ci LIST_HEAD(reaplist); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci spin_lock(&fp->fi_lock); 59862306a36Sopenharmony_ci list_for_each_entry_safe(ls, n, &fp->fi_lo_states, ls_perfile) { 59962306a36Sopenharmony_ci if (ls->ls_stid.sc_client == clp) 60062306a36Sopenharmony_ci nfsd4_return_all_layouts(ls, &reaplist); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci spin_unlock(&fp->fi_lock); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci nfsd4_free_layouts(&reaplist); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void 60862306a36Sopenharmony_cinfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct nfs4_client *clp = ls->ls_stid.sc_client; 61162306a36Sopenharmony_ci char addr_str[INET6_ADDRSTRLEN]; 61262306a36Sopenharmony_ci static char const nfsd_recall_failed[] = "/sbin/nfsd-recall-failed"; 61362306a36Sopenharmony_ci static char *envp[] = { 61462306a36Sopenharmony_ci "HOME=/", 61562306a36Sopenharmony_ci "TERM=linux", 61662306a36Sopenharmony_ci "PATH=/sbin:/usr/sbin:/bin:/usr/bin", 61762306a36Sopenharmony_ci NULL 61862306a36Sopenharmony_ci }; 61962306a36Sopenharmony_ci char *argv[8]; 62062306a36Sopenharmony_ci int error; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci rpc_ntop((struct sockaddr *)&clp->cl_addr, addr_str, sizeof(addr_str)); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci printk(KERN_WARNING 62562306a36Sopenharmony_ci "nfsd: client %s failed to respond to layout recall. " 62662306a36Sopenharmony_ci " Fencing..\n", addr_str); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci argv[0] = (char *)nfsd_recall_failed; 62962306a36Sopenharmony_ci argv[1] = addr_str; 63062306a36Sopenharmony_ci argv[2] = ls->ls_file->nf_file->f_path.mnt->mnt_sb->s_id; 63162306a36Sopenharmony_ci argv[3] = NULL; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci error = call_usermodehelper(nfsd_recall_failed, argv, envp, 63462306a36Sopenharmony_ci UMH_WAIT_PROC); 63562306a36Sopenharmony_ci if (error) { 63662306a36Sopenharmony_ci printk(KERN_ERR "nfsd: fence failed for client %s: %d!\n", 63762306a36Sopenharmony_ci addr_str, error); 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic void 64262306a36Sopenharmony_cinfsd4_cb_layout_prepare(struct nfsd4_callback *cb) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct nfs4_layout_stateid *ls = 64562306a36Sopenharmony_ci container_of(cb, struct nfs4_layout_stateid, ls_recall); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci mutex_lock(&ls->ls_mutex); 64862306a36Sopenharmony_ci nfs4_inc_and_copy_stateid(&ls->ls_recall_sid, &ls->ls_stid); 64962306a36Sopenharmony_ci mutex_unlock(&ls->ls_mutex); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int 65362306a36Sopenharmony_cinfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct nfs4_layout_stateid *ls = 65662306a36Sopenharmony_ci container_of(cb, struct nfs4_layout_stateid, ls_recall); 65762306a36Sopenharmony_ci struct nfsd_net *nn; 65862306a36Sopenharmony_ci ktime_t now, cutoff; 65962306a36Sopenharmony_ci const struct nfsd4_layout_ops *ops; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci trace_nfsd_cb_layout_done(&ls->ls_stid.sc_stateid, task); 66262306a36Sopenharmony_ci switch (task->tk_status) { 66362306a36Sopenharmony_ci case 0: 66462306a36Sopenharmony_ci case -NFS4ERR_DELAY: 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * Anything left? If not, then call it done. Note that we don't 66762306a36Sopenharmony_ci * take the spinlock since this is an optimization and nothing 66862306a36Sopenharmony_ci * should get added until the cb counter goes to zero. 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci if (list_empty(&ls->ls_layouts)) 67162306a36Sopenharmony_ci return 1; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* Poll the client until it's done with the layout */ 67462306a36Sopenharmony_ci now = ktime_get(); 67562306a36Sopenharmony_ci nn = net_generic(ls->ls_stid.sc_client->net, nfsd_net_id); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* Client gets 2 lease periods to return it */ 67862306a36Sopenharmony_ci cutoff = ktime_add_ns(task->tk_start, 67962306a36Sopenharmony_ci (u64)nn->nfsd4_lease * NSEC_PER_SEC * 2); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (ktime_before(now, cutoff)) { 68262306a36Sopenharmony_ci rpc_delay(task, HZ/100); /* 10 mili-seconds */ 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci fallthrough; 68662306a36Sopenharmony_ci default: 68762306a36Sopenharmony_ci /* 68862306a36Sopenharmony_ci * Unknown error or non-responding client, we'll need to fence. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci trace_nfsd_layout_recall_fail(&ls->ls_stid.sc_stateid); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ops = nfsd4_layout_ops[ls->ls_layout_type]; 69362306a36Sopenharmony_ci if (ops->fence_client) 69462306a36Sopenharmony_ci ops->fence_client(ls); 69562306a36Sopenharmony_ci else 69662306a36Sopenharmony_ci nfsd4_cb_layout_fail(ls); 69762306a36Sopenharmony_ci return 1; 69862306a36Sopenharmony_ci case -NFS4ERR_NOMATCHING_LAYOUT: 69962306a36Sopenharmony_ci trace_nfsd_layout_recall_done(&ls->ls_stid.sc_stateid); 70062306a36Sopenharmony_ci task->tk_status = 0; 70162306a36Sopenharmony_ci return 1; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic void 70662306a36Sopenharmony_cinfsd4_cb_layout_release(struct nfsd4_callback *cb) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct nfs4_layout_stateid *ls = 70962306a36Sopenharmony_ci container_of(cb, struct nfs4_layout_stateid, ls_recall); 71062306a36Sopenharmony_ci LIST_HEAD(reaplist); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci trace_nfsd_layout_recall_release(&ls->ls_stid.sc_stateid); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci nfsd4_return_all_layouts(ls, &reaplist); 71562306a36Sopenharmony_ci nfsd4_free_layouts(&reaplist); 71662306a36Sopenharmony_ci nfs4_put_stid(&ls->ls_stid); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic const struct nfsd4_callback_ops nfsd4_cb_layout_ops = { 72062306a36Sopenharmony_ci .prepare = nfsd4_cb_layout_prepare, 72162306a36Sopenharmony_ci .done = nfsd4_cb_layout_done, 72262306a36Sopenharmony_ci .release = nfsd4_cb_layout_release, 72362306a36Sopenharmony_ci}; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic bool 72662306a36Sopenharmony_cinfsd4_layout_lm_break(struct file_lock *fl) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci /* 72962306a36Sopenharmony_ci * We don't want the locks code to timeout the lease for us; 73062306a36Sopenharmony_ci * we'll remove it ourself if a layout isn't returned 73162306a36Sopenharmony_ci * in time: 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci fl->fl_break_time = 0; 73462306a36Sopenharmony_ci nfsd4_recall_file_layout(fl->fl_owner); 73562306a36Sopenharmony_ci return false; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic int 73962306a36Sopenharmony_cinfsd4_layout_lm_change(struct file_lock *onlist, int arg, 74062306a36Sopenharmony_ci struct list_head *dispose) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci BUG_ON(!(arg & F_UNLCK)); 74362306a36Sopenharmony_ci return lease_modify(onlist, arg, dispose); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic const struct lock_manager_operations nfsd4_layouts_lm_ops = { 74762306a36Sopenharmony_ci .lm_break = nfsd4_layout_lm_break, 74862306a36Sopenharmony_ci .lm_change = nfsd4_layout_lm_change, 74962306a36Sopenharmony_ci}; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ciint 75262306a36Sopenharmony_cinfsd4_init_pnfs(void) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci int i; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci for (i = 0; i < DEVID_HASH_SIZE; i++) 75762306a36Sopenharmony_ci INIT_LIST_HEAD(&nfsd_devid_hash[i]); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci nfs4_layout_cache = kmem_cache_create("nfs4_layout", 76062306a36Sopenharmony_ci sizeof(struct nfs4_layout), 0, 0, NULL); 76162306a36Sopenharmony_ci if (!nfs4_layout_cache) 76262306a36Sopenharmony_ci return -ENOMEM; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci nfs4_layout_stateid_cache = kmem_cache_create("nfs4_layout_stateid", 76562306a36Sopenharmony_ci sizeof(struct nfs4_layout_stateid), 0, 0, NULL); 76662306a36Sopenharmony_ci if (!nfs4_layout_stateid_cache) { 76762306a36Sopenharmony_ci kmem_cache_destroy(nfs4_layout_cache); 76862306a36Sopenharmony_ci return -ENOMEM; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_civoid 77462306a36Sopenharmony_cinfsd4_exit_pnfs(void) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci int i; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci kmem_cache_destroy(nfs4_layout_cache); 77962306a36Sopenharmony_ci kmem_cache_destroy(nfs4_layout_stateid_cache); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci for (i = 0; i < DEVID_HASH_SIZE; i++) { 78262306a36Sopenharmony_ci struct nfsd4_deviceid_map *map, *n; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci list_for_each_entry_safe(map, n, &nfsd_devid_hash[i], hash) 78562306a36Sopenharmony_ci kfree(map); 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci} 788