@@ -28,6 +28,7 @@
#include <linux/nfsd/nfs4layoutxdr.h>
#include <linux/sunrpc/addr.h>
+#include "nfsfh.h"
#include "nfsd.h"
#define NFSDDBG_FACILITY NFSDDBG_FILELAYOUT
@@ -351,9 +352,100 @@ static int nfsd4_pnfs_dlm_getdevinfo(struct super_block *sb,
return err;
}
+static int get_stripe_unit(int blocksize)
+{
+ if (blocksize >= NFSSVC_MAXBLKSIZE)
+ return blocksize;
+ return NFSSVC_MAXBLKSIZE - (NFSSVC_MAXBLKSIZE % blocksize);
+}
+
+/*
+ * Look up inode block device in pnfs_dlm_device list.
+ * Hash on the inode->i_ino and number of data servers.
+ */
+static int dlm_ino_hash(struct inode *ino)
+{
+ struct dlm_device_entry *de;
+ u32 hash_mask = 0;
+
+ /* If can't find the inode block device in the pnfs_dlm_deivce list
+ * then don't hand out a layout
+ */
+ de = nfsd4_find_pnfs_dlm_device(ino->i_sb);
+ if (!de)
+ return -1;
+ hash_mask = de->num_ds - 1;
+ return ino->i_ino & hash_mask;
+}
+
+static enum nfsstat4 nfsd4_pnfs_dlm_layoutget(struct inode *inode,
+ struct exp_xdr_stream *xdr,
+ const struct nfsd4_pnfs_layoutget_arg *args,
+ struct nfsd4_pnfs_layoutget_res *res)
+{
+ struct pnfs_filelayout_layout *layout = NULL;
+ struct knfsd_fh *fhp = NULL;
+ int index;
+ enum nfsstat4 rc = NFS4_OK;
+
+ dprintk("%s: LAYOUT_GET\n", __func__);
+
+ index = dlm_ino_hash(inode);
+ dprintk("%s first stripe index %d i_ino %lu\n", __func__, index,
+ inode->i_ino);
+ if (index < 0)
+ return NFS4ERR_LAYOUTUNAVAILABLE;
+
+ res->lg_seg.layout_type = LAYOUT_NFSV4_1_FILES;
+ /* Always give out whole file layouts */
+ res->lg_seg.offset = 0;
+ res->lg_seg.length = NFS4_MAX_UINT64;
+ /* Always give out READ ONLY layouts */
+ res->lg_seg.iomode = IOMODE_READ;
+
+ layout = kzalloc(sizeof(*layout), GFP_KERNEL);
+ if (layout == NULL) {
+ rc = NFS4ERR_LAYOUTTRYLATER;
+ goto error;
+ }
+
+ /* Set file layout response args */
+ layout->lg_layout_type = LAYOUT_NFSV4_1_FILES;
+ layout->lg_stripe_type = STRIPE_SPARSE;
+ layout->lg_commit_through_mds = false;
+ layout->lg_stripe_unit = get_stripe_unit(inode->i_sb->s_blocksize);
+ layout->lg_fh_length = 1;
+ layout->device_id.sbid = args->lg_sbid;
+ layout->device_id.devid = 1; /*FSFTEMP*/
+ layout->lg_first_stripe_index = index; /*FSFTEMP*/
+ layout->lg_pattern_offset = 0;
+
+ fhp = kmalloc(sizeof(*fhp), GFP_KERNEL);
+ if (fhp == NULL) {
+ rc = NFS4ERR_LAYOUTTRYLATER;
+ goto error;
+ }
+
+ memcpy(fhp, args->lg_fh, sizeof(*fhp));
+ pnfs_fh_mark_ds(fhp);
+ layout->lg_fh_list = fhp;
+
+ /* Call nfsd to encode layout */
+ rc = filelayout_encode_layout(xdr, layout);
+exit:
+ kfree(layout);
+ kfree(fhp);
+ return rc;
+
+error:
+ res->lg_seg.length = 0;
+ goto exit;
+}
+
/* For use by DLM cluster file systems exported by pNFSD */
const struct pnfs_export_operations pnfs_dlm_export_ops = {
.get_device_info = nfsd4_pnfs_dlm_getdevinfo,
.get_device_iter = nfsd4_pnfs_dlm_getdeviter,
+ .layout_get = nfsd4_pnfs_dlm_layoutget,
};
EXPORT_SYMBOL(pnfs_dlm_export_ops);