1*9cf514ccSChristoph Hellwig /* 2*9cf514ccSChristoph Hellwig * Copyright (c) 2014 Christoph Hellwig. 3*9cf514ccSChristoph Hellwig */ 4*9cf514ccSChristoph Hellwig #include <linux/jhash.h> 5*9cf514ccSChristoph Hellwig #include <linux/sched.h> 6*9cf514ccSChristoph Hellwig 7*9cf514ccSChristoph Hellwig #include "pnfs.h" 8*9cf514ccSChristoph Hellwig #include "netns.h" 9*9cf514ccSChristoph Hellwig 10*9cf514ccSChristoph Hellwig #define NFSDDBG_FACILITY NFSDDBG_PNFS 11*9cf514ccSChristoph Hellwig 12*9cf514ccSChristoph Hellwig struct nfs4_layout { 13*9cf514ccSChristoph Hellwig struct list_head lo_perstate; 14*9cf514ccSChristoph Hellwig struct nfs4_layout_stateid *lo_state; 15*9cf514ccSChristoph Hellwig struct nfsd4_layout_seg lo_seg; 16*9cf514ccSChristoph Hellwig }; 17*9cf514ccSChristoph Hellwig 18*9cf514ccSChristoph Hellwig static struct kmem_cache *nfs4_layout_cache; 19*9cf514ccSChristoph Hellwig static struct kmem_cache *nfs4_layout_stateid_cache; 20*9cf514ccSChristoph Hellwig 21*9cf514ccSChristoph Hellwig const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = { 22*9cf514ccSChristoph Hellwig }; 23*9cf514ccSChristoph Hellwig 24*9cf514ccSChristoph Hellwig /* pNFS device ID to export fsid mapping */ 25*9cf514ccSChristoph Hellwig #define DEVID_HASH_BITS 8 26*9cf514ccSChristoph Hellwig #define DEVID_HASH_SIZE (1 << DEVID_HASH_BITS) 27*9cf514ccSChristoph Hellwig #define DEVID_HASH_MASK (DEVID_HASH_SIZE - 1) 28*9cf514ccSChristoph Hellwig static u64 nfsd_devid_seq = 1; 29*9cf514ccSChristoph Hellwig static struct list_head nfsd_devid_hash[DEVID_HASH_SIZE]; 30*9cf514ccSChristoph Hellwig static DEFINE_SPINLOCK(nfsd_devid_lock); 31*9cf514ccSChristoph Hellwig 32*9cf514ccSChristoph Hellwig static inline u32 devid_hashfn(u64 idx) 33*9cf514ccSChristoph Hellwig { 34*9cf514ccSChristoph Hellwig return jhash_2words(idx, idx >> 32, 0) & DEVID_HASH_MASK; 35*9cf514ccSChristoph Hellwig } 36*9cf514ccSChristoph Hellwig 37*9cf514ccSChristoph Hellwig static void 38*9cf514ccSChristoph Hellwig nfsd4_alloc_devid_map(const struct svc_fh *fhp) 39*9cf514ccSChristoph Hellwig { 40*9cf514ccSChristoph Hellwig const struct knfsd_fh *fh = &fhp->fh_handle; 41*9cf514ccSChristoph Hellwig size_t fsid_len = key_len(fh->fh_fsid_type); 42*9cf514ccSChristoph Hellwig struct nfsd4_deviceid_map *map, *old; 43*9cf514ccSChristoph Hellwig int i; 44*9cf514ccSChristoph Hellwig 45*9cf514ccSChristoph Hellwig map = kzalloc(sizeof(*map) + fsid_len, GFP_KERNEL); 46*9cf514ccSChristoph Hellwig if (!map) 47*9cf514ccSChristoph Hellwig return; 48*9cf514ccSChristoph Hellwig 49*9cf514ccSChristoph Hellwig map->fsid_type = fh->fh_fsid_type; 50*9cf514ccSChristoph Hellwig memcpy(&map->fsid, fh->fh_fsid, fsid_len); 51*9cf514ccSChristoph Hellwig 52*9cf514ccSChristoph Hellwig spin_lock(&nfsd_devid_lock); 53*9cf514ccSChristoph Hellwig if (fhp->fh_export->ex_devid_map) 54*9cf514ccSChristoph Hellwig goto out_unlock; 55*9cf514ccSChristoph Hellwig 56*9cf514ccSChristoph Hellwig for (i = 0; i < DEVID_HASH_SIZE; i++) { 57*9cf514ccSChristoph Hellwig list_for_each_entry(old, &nfsd_devid_hash[i], hash) { 58*9cf514ccSChristoph Hellwig if (old->fsid_type != fh->fh_fsid_type) 59*9cf514ccSChristoph Hellwig continue; 60*9cf514ccSChristoph Hellwig if (memcmp(old->fsid, fh->fh_fsid, 61*9cf514ccSChristoph Hellwig key_len(old->fsid_type))) 62*9cf514ccSChristoph Hellwig continue; 63*9cf514ccSChristoph Hellwig 64*9cf514ccSChristoph Hellwig fhp->fh_export->ex_devid_map = old; 65*9cf514ccSChristoph Hellwig goto out_unlock; 66*9cf514ccSChristoph Hellwig } 67*9cf514ccSChristoph Hellwig } 68*9cf514ccSChristoph Hellwig 69*9cf514ccSChristoph Hellwig map->idx = nfsd_devid_seq++; 70*9cf514ccSChristoph Hellwig list_add_tail_rcu(&map->hash, &nfsd_devid_hash[devid_hashfn(map->idx)]); 71*9cf514ccSChristoph Hellwig fhp->fh_export->ex_devid_map = map; 72*9cf514ccSChristoph Hellwig map = NULL; 73*9cf514ccSChristoph Hellwig 74*9cf514ccSChristoph Hellwig out_unlock: 75*9cf514ccSChristoph Hellwig spin_unlock(&nfsd_devid_lock); 76*9cf514ccSChristoph Hellwig kfree(map); 77*9cf514ccSChristoph Hellwig } 78*9cf514ccSChristoph Hellwig 79*9cf514ccSChristoph Hellwig struct nfsd4_deviceid_map * 80*9cf514ccSChristoph Hellwig nfsd4_find_devid_map(int idx) 81*9cf514ccSChristoph Hellwig { 82*9cf514ccSChristoph Hellwig struct nfsd4_deviceid_map *map, *ret = NULL; 83*9cf514ccSChristoph Hellwig 84*9cf514ccSChristoph Hellwig rcu_read_lock(); 85*9cf514ccSChristoph Hellwig list_for_each_entry_rcu(map, &nfsd_devid_hash[devid_hashfn(idx)], hash) 86*9cf514ccSChristoph Hellwig if (map->idx == idx) 87*9cf514ccSChristoph Hellwig ret = map; 88*9cf514ccSChristoph Hellwig rcu_read_unlock(); 89*9cf514ccSChristoph Hellwig 90*9cf514ccSChristoph Hellwig return ret; 91*9cf514ccSChristoph Hellwig } 92*9cf514ccSChristoph Hellwig 93*9cf514ccSChristoph Hellwig int 94*9cf514ccSChristoph Hellwig nfsd4_set_deviceid(struct nfsd4_deviceid *id, const struct svc_fh *fhp, 95*9cf514ccSChristoph Hellwig u32 device_generation) 96*9cf514ccSChristoph Hellwig { 97*9cf514ccSChristoph Hellwig if (!fhp->fh_export->ex_devid_map) { 98*9cf514ccSChristoph Hellwig nfsd4_alloc_devid_map(fhp); 99*9cf514ccSChristoph Hellwig if (!fhp->fh_export->ex_devid_map) 100*9cf514ccSChristoph Hellwig return -ENOMEM; 101*9cf514ccSChristoph Hellwig } 102*9cf514ccSChristoph Hellwig 103*9cf514ccSChristoph Hellwig id->fsid_idx = fhp->fh_export->ex_devid_map->idx; 104*9cf514ccSChristoph Hellwig id->generation = device_generation; 105*9cf514ccSChristoph Hellwig id->pad = 0; 106*9cf514ccSChristoph Hellwig return 0; 107*9cf514ccSChristoph Hellwig } 108*9cf514ccSChristoph Hellwig 109*9cf514ccSChristoph Hellwig void nfsd4_setup_layout_type(struct svc_export *exp) 110*9cf514ccSChristoph Hellwig { 111*9cf514ccSChristoph Hellwig if (exp->ex_flags & NFSEXP_NOPNFS) 112*9cf514ccSChristoph Hellwig return; 113*9cf514ccSChristoph Hellwig } 114*9cf514ccSChristoph Hellwig 115*9cf514ccSChristoph Hellwig static void 116*9cf514ccSChristoph Hellwig nfsd4_free_layout_stateid(struct nfs4_stid *stid) 117*9cf514ccSChristoph Hellwig { 118*9cf514ccSChristoph Hellwig struct nfs4_layout_stateid *ls = layoutstateid(stid); 119*9cf514ccSChristoph Hellwig struct nfs4_client *clp = ls->ls_stid.sc_client; 120*9cf514ccSChristoph Hellwig struct nfs4_file *fp = ls->ls_stid.sc_file; 121*9cf514ccSChristoph Hellwig 122*9cf514ccSChristoph Hellwig spin_lock(&clp->cl_lock); 123*9cf514ccSChristoph Hellwig list_del_init(&ls->ls_perclnt); 124*9cf514ccSChristoph Hellwig spin_unlock(&clp->cl_lock); 125*9cf514ccSChristoph Hellwig 126*9cf514ccSChristoph Hellwig spin_lock(&fp->fi_lock); 127*9cf514ccSChristoph Hellwig list_del_init(&ls->ls_perfile); 128*9cf514ccSChristoph Hellwig spin_unlock(&fp->fi_lock); 129*9cf514ccSChristoph Hellwig 130*9cf514ccSChristoph Hellwig kmem_cache_free(nfs4_layout_stateid_cache, ls); 131*9cf514ccSChristoph Hellwig } 132*9cf514ccSChristoph Hellwig 133*9cf514ccSChristoph Hellwig static struct nfs4_layout_stateid * 134*9cf514ccSChristoph Hellwig nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, 135*9cf514ccSChristoph Hellwig struct nfs4_stid *parent, u32 layout_type) 136*9cf514ccSChristoph Hellwig { 137*9cf514ccSChristoph Hellwig struct nfs4_client *clp = cstate->clp; 138*9cf514ccSChristoph Hellwig struct nfs4_file *fp = parent->sc_file; 139*9cf514ccSChristoph Hellwig struct nfs4_layout_stateid *ls; 140*9cf514ccSChristoph Hellwig struct nfs4_stid *stp; 141*9cf514ccSChristoph Hellwig 142*9cf514ccSChristoph Hellwig stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache); 143*9cf514ccSChristoph Hellwig if (!stp) 144*9cf514ccSChristoph Hellwig return NULL; 145*9cf514ccSChristoph Hellwig stp->sc_free = nfsd4_free_layout_stateid; 146*9cf514ccSChristoph Hellwig get_nfs4_file(fp); 147*9cf514ccSChristoph Hellwig stp->sc_file = fp; 148*9cf514ccSChristoph Hellwig 149*9cf514ccSChristoph Hellwig ls = layoutstateid(stp); 150*9cf514ccSChristoph Hellwig INIT_LIST_HEAD(&ls->ls_perclnt); 151*9cf514ccSChristoph Hellwig INIT_LIST_HEAD(&ls->ls_perfile); 152*9cf514ccSChristoph Hellwig spin_lock_init(&ls->ls_lock); 153*9cf514ccSChristoph Hellwig INIT_LIST_HEAD(&ls->ls_layouts); 154*9cf514ccSChristoph Hellwig ls->ls_layout_type = layout_type; 155*9cf514ccSChristoph Hellwig 156*9cf514ccSChristoph Hellwig spin_lock(&clp->cl_lock); 157*9cf514ccSChristoph Hellwig stp->sc_type = NFS4_LAYOUT_STID; 158*9cf514ccSChristoph Hellwig list_add(&ls->ls_perclnt, &clp->cl_lo_states); 159*9cf514ccSChristoph Hellwig spin_unlock(&clp->cl_lock); 160*9cf514ccSChristoph Hellwig 161*9cf514ccSChristoph Hellwig spin_lock(&fp->fi_lock); 162*9cf514ccSChristoph Hellwig list_add(&ls->ls_perfile, &fp->fi_lo_states); 163*9cf514ccSChristoph Hellwig spin_unlock(&fp->fi_lock); 164*9cf514ccSChristoph Hellwig 165*9cf514ccSChristoph Hellwig return ls; 166*9cf514ccSChristoph Hellwig } 167*9cf514ccSChristoph Hellwig 168*9cf514ccSChristoph Hellwig __be32 169*9cf514ccSChristoph Hellwig nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp, 170*9cf514ccSChristoph Hellwig struct nfsd4_compound_state *cstate, stateid_t *stateid, 171*9cf514ccSChristoph Hellwig bool create, u32 layout_type, struct nfs4_layout_stateid **lsp) 172*9cf514ccSChristoph Hellwig { 173*9cf514ccSChristoph Hellwig struct nfs4_layout_stateid *ls; 174*9cf514ccSChristoph Hellwig struct nfs4_stid *stid; 175*9cf514ccSChristoph Hellwig unsigned char typemask = NFS4_LAYOUT_STID; 176*9cf514ccSChristoph Hellwig __be32 status; 177*9cf514ccSChristoph Hellwig 178*9cf514ccSChristoph Hellwig if (create) 179*9cf514ccSChristoph Hellwig typemask |= (NFS4_OPEN_STID | NFS4_LOCK_STID | NFS4_DELEG_STID); 180*9cf514ccSChristoph Hellwig 181*9cf514ccSChristoph Hellwig status = nfsd4_lookup_stateid(cstate, stateid, typemask, &stid, 182*9cf514ccSChristoph Hellwig net_generic(SVC_NET(rqstp), nfsd_net_id)); 183*9cf514ccSChristoph Hellwig if (status) 184*9cf514ccSChristoph Hellwig goto out; 185*9cf514ccSChristoph Hellwig 186*9cf514ccSChristoph Hellwig if (!fh_match(&cstate->current_fh.fh_handle, 187*9cf514ccSChristoph Hellwig &stid->sc_file->fi_fhandle)) { 188*9cf514ccSChristoph Hellwig status = nfserr_bad_stateid; 189*9cf514ccSChristoph Hellwig goto out_put_stid; 190*9cf514ccSChristoph Hellwig } 191*9cf514ccSChristoph Hellwig 192*9cf514ccSChristoph Hellwig if (stid->sc_type != NFS4_LAYOUT_STID) { 193*9cf514ccSChristoph Hellwig ls = nfsd4_alloc_layout_stateid(cstate, stid, layout_type); 194*9cf514ccSChristoph Hellwig nfs4_put_stid(stid); 195*9cf514ccSChristoph Hellwig 196*9cf514ccSChristoph Hellwig status = nfserr_jukebox; 197*9cf514ccSChristoph Hellwig if (!ls) 198*9cf514ccSChristoph Hellwig goto out; 199*9cf514ccSChristoph Hellwig } else { 200*9cf514ccSChristoph Hellwig ls = container_of(stid, struct nfs4_layout_stateid, ls_stid); 201*9cf514ccSChristoph Hellwig 202*9cf514ccSChristoph Hellwig status = nfserr_bad_stateid; 203*9cf514ccSChristoph Hellwig if (stateid->si_generation > stid->sc_stateid.si_generation) 204*9cf514ccSChristoph Hellwig goto out_put_stid; 205*9cf514ccSChristoph Hellwig if (layout_type != ls->ls_layout_type) 206*9cf514ccSChristoph Hellwig goto out_put_stid; 207*9cf514ccSChristoph Hellwig } 208*9cf514ccSChristoph Hellwig 209*9cf514ccSChristoph Hellwig *lsp = ls; 210*9cf514ccSChristoph Hellwig return 0; 211*9cf514ccSChristoph Hellwig 212*9cf514ccSChristoph Hellwig out_put_stid: 213*9cf514ccSChristoph Hellwig nfs4_put_stid(stid); 214*9cf514ccSChristoph Hellwig out: 215*9cf514ccSChristoph Hellwig return status; 216*9cf514ccSChristoph Hellwig } 217*9cf514ccSChristoph Hellwig 218*9cf514ccSChristoph Hellwig static inline u64 219*9cf514ccSChristoph Hellwig layout_end(struct nfsd4_layout_seg *seg) 220*9cf514ccSChristoph Hellwig { 221*9cf514ccSChristoph Hellwig u64 end = seg->offset + seg->length; 222*9cf514ccSChristoph Hellwig return end >= seg->offset ? end : NFS4_MAX_UINT64; 223*9cf514ccSChristoph Hellwig } 224*9cf514ccSChristoph Hellwig 225*9cf514ccSChristoph Hellwig static void 226*9cf514ccSChristoph Hellwig layout_update_len(struct nfsd4_layout_seg *lo, u64 end) 227*9cf514ccSChristoph Hellwig { 228*9cf514ccSChristoph Hellwig if (end == NFS4_MAX_UINT64) 229*9cf514ccSChristoph Hellwig lo->length = NFS4_MAX_UINT64; 230*9cf514ccSChristoph Hellwig else 231*9cf514ccSChristoph Hellwig lo->length = end - lo->offset; 232*9cf514ccSChristoph Hellwig } 233*9cf514ccSChristoph Hellwig 234*9cf514ccSChristoph Hellwig static bool 235*9cf514ccSChristoph Hellwig layouts_overlapping(struct nfs4_layout *lo, struct nfsd4_layout_seg *s) 236*9cf514ccSChristoph Hellwig { 237*9cf514ccSChristoph Hellwig if (s->iomode != IOMODE_ANY && s->iomode != lo->lo_seg.iomode) 238*9cf514ccSChristoph Hellwig return false; 239*9cf514ccSChristoph Hellwig if (layout_end(&lo->lo_seg) <= s->offset) 240*9cf514ccSChristoph Hellwig return false; 241*9cf514ccSChristoph Hellwig if (layout_end(s) <= lo->lo_seg.offset) 242*9cf514ccSChristoph Hellwig return false; 243*9cf514ccSChristoph Hellwig return true; 244*9cf514ccSChristoph Hellwig } 245*9cf514ccSChristoph Hellwig 246*9cf514ccSChristoph Hellwig static bool 247*9cf514ccSChristoph Hellwig layouts_try_merge(struct nfsd4_layout_seg *lo, struct nfsd4_layout_seg *new) 248*9cf514ccSChristoph Hellwig { 249*9cf514ccSChristoph Hellwig if (lo->iomode != new->iomode) 250*9cf514ccSChristoph Hellwig return false; 251*9cf514ccSChristoph Hellwig if (layout_end(new) < lo->offset) 252*9cf514ccSChristoph Hellwig return false; 253*9cf514ccSChristoph Hellwig if (layout_end(lo) < new->offset) 254*9cf514ccSChristoph Hellwig return false; 255*9cf514ccSChristoph Hellwig 256*9cf514ccSChristoph Hellwig lo->offset = min(lo->offset, new->offset); 257*9cf514ccSChristoph Hellwig layout_update_len(lo, max(layout_end(lo), layout_end(new))); 258*9cf514ccSChristoph Hellwig return true; 259*9cf514ccSChristoph Hellwig } 260*9cf514ccSChristoph Hellwig 261*9cf514ccSChristoph Hellwig __be32 262*9cf514ccSChristoph Hellwig nfsd4_insert_layout(struct nfsd4_layoutget *lgp, struct nfs4_layout_stateid *ls) 263*9cf514ccSChristoph Hellwig { 264*9cf514ccSChristoph Hellwig struct nfsd4_layout_seg *seg = &lgp->lg_seg; 265*9cf514ccSChristoph Hellwig struct nfs4_layout *lp, *new = NULL; 266*9cf514ccSChristoph Hellwig 267*9cf514ccSChristoph Hellwig spin_lock(&ls->ls_lock); 268*9cf514ccSChristoph Hellwig list_for_each_entry(lp, &ls->ls_layouts, lo_perstate) { 269*9cf514ccSChristoph Hellwig if (layouts_try_merge(&lp->lo_seg, seg)) 270*9cf514ccSChristoph Hellwig goto done; 271*9cf514ccSChristoph Hellwig } 272*9cf514ccSChristoph Hellwig spin_unlock(&ls->ls_lock); 273*9cf514ccSChristoph Hellwig 274*9cf514ccSChristoph Hellwig new = kmem_cache_alloc(nfs4_layout_cache, GFP_KERNEL); 275*9cf514ccSChristoph Hellwig if (!new) 276*9cf514ccSChristoph Hellwig return nfserr_jukebox; 277*9cf514ccSChristoph Hellwig memcpy(&new->lo_seg, seg, sizeof(lp->lo_seg)); 278*9cf514ccSChristoph Hellwig new->lo_state = ls; 279*9cf514ccSChristoph Hellwig 280*9cf514ccSChristoph Hellwig spin_lock(&ls->ls_lock); 281*9cf514ccSChristoph Hellwig list_for_each_entry(lp, &ls->ls_layouts, lo_perstate) { 282*9cf514ccSChristoph Hellwig if (layouts_try_merge(&lp->lo_seg, seg)) 283*9cf514ccSChristoph Hellwig goto done; 284*9cf514ccSChristoph Hellwig } 285*9cf514ccSChristoph Hellwig 286*9cf514ccSChristoph Hellwig atomic_inc(&ls->ls_stid.sc_count); 287*9cf514ccSChristoph Hellwig list_add_tail(&new->lo_perstate, &ls->ls_layouts); 288*9cf514ccSChristoph Hellwig new = NULL; 289*9cf514ccSChristoph Hellwig done: 290*9cf514ccSChristoph Hellwig update_stateid(&ls->ls_stid.sc_stateid); 291*9cf514ccSChristoph Hellwig memcpy(&lgp->lg_sid, &ls->ls_stid.sc_stateid, sizeof(stateid_t)); 292*9cf514ccSChristoph Hellwig spin_unlock(&ls->ls_lock); 293*9cf514ccSChristoph Hellwig if (new) 294*9cf514ccSChristoph Hellwig kmem_cache_free(nfs4_layout_cache, new); 295*9cf514ccSChristoph Hellwig return nfs_ok; 296*9cf514ccSChristoph Hellwig } 297*9cf514ccSChristoph Hellwig 298*9cf514ccSChristoph Hellwig static void 299*9cf514ccSChristoph Hellwig nfsd4_free_layouts(struct list_head *reaplist) 300*9cf514ccSChristoph Hellwig { 301*9cf514ccSChristoph Hellwig while (!list_empty(reaplist)) { 302*9cf514ccSChristoph Hellwig struct nfs4_layout *lp = list_first_entry(reaplist, 303*9cf514ccSChristoph Hellwig struct nfs4_layout, lo_perstate); 304*9cf514ccSChristoph Hellwig 305*9cf514ccSChristoph Hellwig list_del(&lp->lo_perstate); 306*9cf514ccSChristoph Hellwig nfs4_put_stid(&lp->lo_state->ls_stid); 307*9cf514ccSChristoph Hellwig kmem_cache_free(nfs4_layout_cache, lp); 308*9cf514ccSChristoph Hellwig } 309*9cf514ccSChristoph Hellwig } 310*9cf514ccSChristoph Hellwig 311*9cf514ccSChristoph Hellwig static void 312*9cf514ccSChristoph Hellwig nfsd4_return_file_layout(struct nfs4_layout *lp, struct nfsd4_layout_seg *seg, 313*9cf514ccSChristoph Hellwig struct list_head *reaplist) 314*9cf514ccSChristoph Hellwig { 315*9cf514ccSChristoph Hellwig struct nfsd4_layout_seg *lo = &lp->lo_seg; 316*9cf514ccSChristoph Hellwig u64 end = layout_end(lo); 317*9cf514ccSChristoph Hellwig 318*9cf514ccSChristoph Hellwig if (seg->offset <= lo->offset) { 319*9cf514ccSChristoph Hellwig if (layout_end(seg) >= end) { 320*9cf514ccSChristoph Hellwig list_move_tail(&lp->lo_perstate, reaplist); 321*9cf514ccSChristoph Hellwig return; 322*9cf514ccSChristoph Hellwig } 323*9cf514ccSChristoph Hellwig end = seg->offset; 324*9cf514ccSChristoph Hellwig } else { 325*9cf514ccSChristoph Hellwig /* retain the whole layout segment on a split. */ 326*9cf514ccSChristoph Hellwig if (layout_end(seg) < end) { 327*9cf514ccSChristoph Hellwig dprintk("%s: split not supported\n", __func__); 328*9cf514ccSChristoph Hellwig return; 329*9cf514ccSChristoph Hellwig } 330*9cf514ccSChristoph Hellwig 331*9cf514ccSChristoph Hellwig lo->offset = layout_end(seg); 332*9cf514ccSChristoph Hellwig } 333*9cf514ccSChristoph Hellwig 334*9cf514ccSChristoph Hellwig layout_update_len(lo, end); 335*9cf514ccSChristoph Hellwig } 336*9cf514ccSChristoph Hellwig 337*9cf514ccSChristoph Hellwig __be32 338*9cf514ccSChristoph Hellwig nfsd4_return_file_layouts(struct svc_rqst *rqstp, 339*9cf514ccSChristoph Hellwig struct nfsd4_compound_state *cstate, 340*9cf514ccSChristoph Hellwig struct nfsd4_layoutreturn *lrp) 341*9cf514ccSChristoph Hellwig { 342*9cf514ccSChristoph Hellwig struct nfs4_layout_stateid *ls; 343*9cf514ccSChristoph Hellwig struct nfs4_layout *lp, *n; 344*9cf514ccSChristoph Hellwig LIST_HEAD(reaplist); 345*9cf514ccSChristoph Hellwig __be32 nfserr; 346*9cf514ccSChristoph Hellwig int found = 0; 347*9cf514ccSChristoph Hellwig 348*9cf514ccSChristoph Hellwig nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lrp->lr_sid, 349*9cf514ccSChristoph Hellwig false, lrp->lr_layout_type, 350*9cf514ccSChristoph Hellwig &ls); 351*9cf514ccSChristoph Hellwig if (nfserr) 352*9cf514ccSChristoph Hellwig return nfserr; 353*9cf514ccSChristoph Hellwig 354*9cf514ccSChristoph Hellwig spin_lock(&ls->ls_lock); 355*9cf514ccSChristoph Hellwig list_for_each_entry_safe(lp, n, &ls->ls_layouts, lo_perstate) { 356*9cf514ccSChristoph Hellwig if (layouts_overlapping(lp, &lrp->lr_seg)) { 357*9cf514ccSChristoph Hellwig nfsd4_return_file_layout(lp, &lrp->lr_seg, &reaplist); 358*9cf514ccSChristoph Hellwig found++; 359*9cf514ccSChristoph Hellwig } 360*9cf514ccSChristoph Hellwig } 361*9cf514ccSChristoph Hellwig if (!list_empty(&ls->ls_layouts)) { 362*9cf514ccSChristoph Hellwig if (found) { 363*9cf514ccSChristoph Hellwig update_stateid(&ls->ls_stid.sc_stateid); 364*9cf514ccSChristoph Hellwig memcpy(&lrp->lr_sid, &ls->ls_stid.sc_stateid, 365*9cf514ccSChristoph Hellwig sizeof(stateid_t)); 366*9cf514ccSChristoph Hellwig } 367*9cf514ccSChristoph Hellwig lrp->lrs_present = 1; 368*9cf514ccSChristoph Hellwig } else { 369*9cf514ccSChristoph Hellwig nfs4_unhash_stid(&ls->ls_stid); 370*9cf514ccSChristoph Hellwig lrp->lrs_present = 0; 371*9cf514ccSChristoph Hellwig } 372*9cf514ccSChristoph Hellwig spin_unlock(&ls->ls_lock); 373*9cf514ccSChristoph Hellwig 374*9cf514ccSChristoph Hellwig nfs4_put_stid(&ls->ls_stid); 375*9cf514ccSChristoph Hellwig nfsd4_free_layouts(&reaplist); 376*9cf514ccSChristoph Hellwig return nfs_ok; 377*9cf514ccSChristoph Hellwig } 378*9cf514ccSChristoph Hellwig 379*9cf514ccSChristoph Hellwig __be32 380*9cf514ccSChristoph Hellwig nfsd4_return_client_layouts(struct svc_rqst *rqstp, 381*9cf514ccSChristoph Hellwig struct nfsd4_compound_state *cstate, 382*9cf514ccSChristoph Hellwig struct nfsd4_layoutreturn *lrp) 383*9cf514ccSChristoph Hellwig { 384*9cf514ccSChristoph Hellwig struct nfs4_layout_stateid *ls, *n; 385*9cf514ccSChristoph Hellwig struct nfs4_client *clp = cstate->clp; 386*9cf514ccSChristoph Hellwig struct nfs4_layout *lp, *t; 387*9cf514ccSChristoph Hellwig LIST_HEAD(reaplist); 388*9cf514ccSChristoph Hellwig 389*9cf514ccSChristoph Hellwig lrp->lrs_present = 0; 390*9cf514ccSChristoph Hellwig 391*9cf514ccSChristoph Hellwig spin_lock(&clp->cl_lock); 392*9cf514ccSChristoph Hellwig list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) { 393*9cf514ccSChristoph Hellwig if (lrp->lr_return_type == RETURN_FSID && 394*9cf514ccSChristoph Hellwig !fh_fsid_match(&ls->ls_stid.sc_file->fi_fhandle, 395*9cf514ccSChristoph Hellwig &cstate->current_fh.fh_handle)) 396*9cf514ccSChristoph Hellwig continue; 397*9cf514ccSChristoph Hellwig 398*9cf514ccSChristoph Hellwig spin_lock(&ls->ls_lock); 399*9cf514ccSChristoph Hellwig list_for_each_entry_safe(lp, t, &ls->ls_layouts, lo_perstate) { 400*9cf514ccSChristoph Hellwig if (lrp->lr_seg.iomode == IOMODE_ANY || 401*9cf514ccSChristoph Hellwig lrp->lr_seg.iomode == lp->lo_seg.iomode) 402*9cf514ccSChristoph Hellwig list_move_tail(&lp->lo_perstate, &reaplist); 403*9cf514ccSChristoph Hellwig } 404*9cf514ccSChristoph Hellwig spin_unlock(&ls->ls_lock); 405*9cf514ccSChristoph Hellwig } 406*9cf514ccSChristoph Hellwig spin_unlock(&clp->cl_lock); 407*9cf514ccSChristoph Hellwig 408*9cf514ccSChristoph Hellwig nfsd4_free_layouts(&reaplist); 409*9cf514ccSChristoph Hellwig return 0; 410*9cf514ccSChristoph Hellwig } 411*9cf514ccSChristoph Hellwig 412*9cf514ccSChristoph Hellwig static void 413*9cf514ccSChristoph Hellwig nfsd4_return_all_layouts(struct nfs4_layout_stateid *ls, 414*9cf514ccSChristoph Hellwig struct list_head *reaplist) 415*9cf514ccSChristoph Hellwig { 416*9cf514ccSChristoph Hellwig spin_lock(&ls->ls_lock); 417*9cf514ccSChristoph Hellwig list_splice_init(&ls->ls_layouts, reaplist); 418*9cf514ccSChristoph Hellwig spin_unlock(&ls->ls_lock); 419*9cf514ccSChristoph Hellwig } 420*9cf514ccSChristoph Hellwig 421*9cf514ccSChristoph Hellwig void 422*9cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(struct nfs4_client *clp) 423*9cf514ccSChristoph Hellwig { 424*9cf514ccSChristoph Hellwig struct nfs4_layout_stateid *ls, *n; 425*9cf514ccSChristoph Hellwig LIST_HEAD(reaplist); 426*9cf514ccSChristoph Hellwig 427*9cf514ccSChristoph Hellwig spin_lock(&clp->cl_lock); 428*9cf514ccSChristoph Hellwig list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) 429*9cf514ccSChristoph Hellwig nfsd4_return_all_layouts(ls, &reaplist); 430*9cf514ccSChristoph Hellwig spin_unlock(&clp->cl_lock); 431*9cf514ccSChristoph Hellwig 432*9cf514ccSChristoph Hellwig nfsd4_free_layouts(&reaplist); 433*9cf514ccSChristoph Hellwig } 434*9cf514ccSChristoph Hellwig 435*9cf514ccSChristoph Hellwig void 436*9cf514ccSChristoph Hellwig nfsd4_return_all_file_layouts(struct nfs4_client *clp, struct nfs4_file *fp) 437*9cf514ccSChristoph Hellwig { 438*9cf514ccSChristoph Hellwig struct nfs4_layout_stateid *ls, *n; 439*9cf514ccSChristoph Hellwig LIST_HEAD(reaplist); 440*9cf514ccSChristoph Hellwig 441*9cf514ccSChristoph Hellwig spin_lock(&fp->fi_lock); 442*9cf514ccSChristoph Hellwig list_for_each_entry_safe(ls, n, &fp->fi_lo_states, ls_perfile) { 443*9cf514ccSChristoph Hellwig if (ls->ls_stid.sc_client == clp) 444*9cf514ccSChristoph Hellwig nfsd4_return_all_layouts(ls, &reaplist); 445*9cf514ccSChristoph Hellwig } 446*9cf514ccSChristoph Hellwig spin_unlock(&fp->fi_lock); 447*9cf514ccSChristoph Hellwig 448*9cf514ccSChristoph Hellwig nfsd4_free_layouts(&reaplist); 449*9cf514ccSChristoph Hellwig } 450*9cf514ccSChristoph Hellwig 451*9cf514ccSChristoph Hellwig int 452*9cf514ccSChristoph Hellwig nfsd4_init_pnfs(void) 453*9cf514ccSChristoph Hellwig { 454*9cf514ccSChristoph Hellwig int i; 455*9cf514ccSChristoph Hellwig 456*9cf514ccSChristoph Hellwig for (i = 0; i < DEVID_HASH_SIZE; i++) 457*9cf514ccSChristoph Hellwig INIT_LIST_HEAD(&nfsd_devid_hash[i]); 458*9cf514ccSChristoph Hellwig 459*9cf514ccSChristoph Hellwig nfs4_layout_cache = kmem_cache_create("nfs4_layout", 460*9cf514ccSChristoph Hellwig sizeof(struct nfs4_layout), 0, 0, NULL); 461*9cf514ccSChristoph Hellwig if (!nfs4_layout_cache) 462*9cf514ccSChristoph Hellwig return -ENOMEM; 463*9cf514ccSChristoph Hellwig 464*9cf514ccSChristoph Hellwig nfs4_layout_stateid_cache = kmem_cache_create("nfs4_layout_stateid", 465*9cf514ccSChristoph Hellwig sizeof(struct nfs4_layout_stateid), 0, 0, NULL); 466*9cf514ccSChristoph Hellwig if (!nfs4_layout_stateid_cache) { 467*9cf514ccSChristoph Hellwig kmem_cache_destroy(nfs4_layout_cache); 468*9cf514ccSChristoph Hellwig return -ENOMEM; 469*9cf514ccSChristoph Hellwig } 470*9cf514ccSChristoph Hellwig return 0; 471*9cf514ccSChristoph Hellwig } 472*9cf514ccSChristoph Hellwig 473*9cf514ccSChristoph Hellwig void 474*9cf514ccSChristoph Hellwig nfsd4_exit_pnfs(void) 475*9cf514ccSChristoph Hellwig { 476*9cf514ccSChristoph Hellwig int i; 477*9cf514ccSChristoph Hellwig 478*9cf514ccSChristoph Hellwig kmem_cache_destroy(nfs4_layout_cache); 479*9cf514ccSChristoph Hellwig kmem_cache_destroy(nfs4_layout_stateid_cache); 480*9cf514ccSChristoph Hellwig 481*9cf514ccSChristoph Hellwig for (i = 0; i < DEVID_HASH_SIZE; i++) { 482*9cf514ccSChristoph Hellwig struct nfsd4_deviceid_map *map, *n; 483*9cf514ccSChristoph Hellwig 484*9cf514ccSChristoph Hellwig list_for_each_entry_safe(map, n, &nfsd_devid_hash[i], hash) 485*9cf514ccSChristoph Hellwig kfree(map); 486*9cf514ccSChristoph Hellwig } 487*9cf514ccSChristoph Hellwig } 488