162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Tom Haynes <loghyr@primarydata.com> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * The following implements a super-simple flex-file server 662306a36Sopenharmony_ci * where the NFSv4.1 mds is also the ds. And the storage is 762306a36Sopenharmony_ci * the same. I.e., writing to the mds via a NFSv4.1 WRITE 862306a36Sopenharmony_ci * goes to the same location as the NFSv3 WRITE. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/nfsd/debug.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/sunrpc/addr.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "flexfilelayoutxdr.h" 1762306a36Sopenharmony_ci#include "pnfs.h" 1862306a36Sopenharmony_ci#include "vfs.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define NFSDDBG_FACILITY NFSDDBG_PNFS 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic __be32 2362306a36Sopenharmony_cinfsd4_ff_proc_layoutget(struct inode *inode, const struct svc_fh *fhp, 2462306a36Sopenharmony_ci struct nfsd4_layoutget *args) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct nfsd4_layout_seg *seg = &args->lg_seg; 2762306a36Sopenharmony_ci u32 device_generation = 0; 2862306a36Sopenharmony_ci int error; 2962306a36Sopenharmony_ci uid_t u; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci struct pnfs_ff_layout *fl; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* 3462306a36Sopenharmony_ci * The super simple flex file server has 1 mirror, 1 data server, 3562306a36Sopenharmony_ci * and 1 file handle. So instead of 4 allocs, do 1 for now. 3662306a36Sopenharmony_ci * Zero it out for the stateid - don't want junk in there! 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci error = -ENOMEM; 3962306a36Sopenharmony_ci fl = kzalloc(sizeof(*fl), GFP_KERNEL); 4062306a36Sopenharmony_ci if (!fl) 4162306a36Sopenharmony_ci goto out_error; 4262306a36Sopenharmony_ci args->lg_content = fl; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* 4562306a36Sopenharmony_ci * Avoid layout commit, try to force the I/O to the DS, 4662306a36Sopenharmony_ci * and for fun, cause all IOMODE_RW layout segments to 4762306a36Sopenharmony_ci * effectively be WRITE only. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci fl->flags = FF_FLAGS_NO_LAYOUTCOMMIT | FF_FLAGS_NO_IO_THRU_MDS | 5062306a36Sopenharmony_ci FF_FLAGS_NO_READ_IO; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* Do not allow a IOMODE_READ segment to have write pemissions */ 5362306a36Sopenharmony_ci if (seg->iomode == IOMODE_READ) { 5462306a36Sopenharmony_ci u = from_kuid(&init_user_ns, inode->i_uid) + 1; 5562306a36Sopenharmony_ci fl->uid = make_kuid(&init_user_ns, u); 5662306a36Sopenharmony_ci } else 5762306a36Sopenharmony_ci fl->uid = inode->i_uid; 5862306a36Sopenharmony_ci fl->gid = inode->i_gid; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci error = nfsd4_set_deviceid(&fl->deviceid, fhp, device_generation); 6162306a36Sopenharmony_ci if (error) 6262306a36Sopenharmony_ci goto out_error; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci fl->fh.size = fhp->fh_handle.fh_size; 6562306a36Sopenharmony_ci memcpy(fl->fh.data, &fhp->fh_handle.fh_raw, fl->fh.size); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* Give whole file layout segments */ 6862306a36Sopenharmony_ci seg->offset = 0; 6962306a36Sopenharmony_ci seg->length = NFS4_MAX_UINT64; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci dprintk("GET: 0x%llx:0x%llx %d\n", seg->offset, seg->length, 7262306a36Sopenharmony_ci seg->iomode); 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciout_error: 7662306a36Sopenharmony_ci seg->length = 0; 7762306a36Sopenharmony_ci return nfserrno(error); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic __be32 8162306a36Sopenharmony_cinfsd4_ff_proc_getdeviceinfo(struct super_block *sb, struct svc_rqst *rqstp, 8262306a36Sopenharmony_ci struct nfs4_client *clp, struct nfsd4_getdeviceinfo *gdp) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct pnfs_ff_device_addr *da; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci u16 port; 8762306a36Sopenharmony_ci char addr[INET6_ADDRSTRLEN]; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci da = kzalloc(sizeof(struct pnfs_ff_device_addr), GFP_KERNEL); 9062306a36Sopenharmony_ci if (!da) 9162306a36Sopenharmony_ci return nfserrno(-ENOMEM); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci gdp->gd_device = da; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci da->version = 3; 9662306a36Sopenharmony_ci da->minor_version = 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci da->rsize = svc_max_payload(rqstp); 9962306a36Sopenharmony_ci da->wsize = da->rsize; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci rpc_ntop((struct sockaddr *)&rqstp->rq_daddr, 10262306a36Sopenharmony_ci addr, INET6_ADDRSTRLEN); 10362306a36Sopenharmony_ci if (rqstp->rq_daddr.ss_family == AF_INET) { 10462306a36Sopenharmony_ci struct sockaddr_in *sin; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci sin = (struct sockaddr_in *)&rqstp->rq_daddr; 10762306a36Sopenharmony_ci port = ntohs(sin->sin_port); 10862306a36Sopenharmony_ci snprintf(da->netaddr.netid, FF_NETID_LEN + 1, "tcp"); 10962306a36Sopenharmony_ci da->netaddr.netid_len = 3; 11062306a36Sopenharmony_ci } else { 11162306a36Sopenharmony_ci struct sockaddr_in6 *sin6; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci sin6 = (struct sockaddr_in6 *)&rqstp->rq_daddr; 11462306a36Sopenharmony_ci port = ntohs(sin6->sin6_port); 11562306a36Sopenharmony_ci snprintf(da->netaddr.netid, FF_NETID_LEN + 1, "tcp6"); 11662306a36Sopenharmony_ci da->netaddr.netid_len = 4; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci da->netaddr.addr_len = 12062306a36Sopenharmony_ci snprintf(da->netaddr.addr, FF_ADDR_LEN + 1, 12162306a36Sopenharmony_ci "%s.%d.%d", addr, port >> 8, port & 0xff); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci da->tightly_coupled = false; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciconst struct nfsd4_layout_ops ff_layout_ops = { 12962306a36Sopenharmony_ci .notify_types = 13062306a36Sopenharmony_ci NOTIFY_DEVICEID4_DELETE | NOTIFY_DEVICEID4_CHANGE, 13162306a36Sopenharmony_ci .disable_recalls = true, 13262306a36Sopenharmony_ci .proc_getdeviceinfo = nfsd4_ff_proc_getdeviceinfo, 13362306a36Sopenharmony_ci .encode_getdeviceinfo = nfsd4_ff_encode_getdeviceinfo, 13462306a36Sopenharmony_ci .proc_layoutget = nfsd4_ff_proc_layoutget, 13562306a36Sopenharmony_ci .encode_layoutget = nfsd4_ff_encode_layoutget, 13662306a36Sopenharmony_ci}; 137