From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 406YCB3wMszF1xS for ; Fri, 23 Mar 2018 04:12:53 +1100 (AEDT) Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w2MH9quc064317 for ; Thu, 22 Mar 2018 13:12:50 -0400 Received: from e06smtp12.uk.ibm.com (e06smtp12.uk.ibm.com [195.75.94.108]) by mx0a-001b2d01.pphosted.com with ESMTP id 2gvetvp0fv-1 (version=TLSv1.2 cipher=AES256-SHA256 bits=256 verify=NOT) for ; Thu, 22 Mar 2018 13:12:49 -0400 Received: from localhost by e06smtp12.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 22 Mar 2018 17:12:47 -0000 Subject: Re: [PATCH v2 13/38] cxlflash: Support adapter file descriptors for OCXL To: Uma Krishnan , linux-scsi@vger.kernel.org, James Bottomley , "Martin K. Petersen" , "Matthew R. Ochs" , "Manoj N. Kumar" Cc: linuxppc-dev@lists.ozlabs.org, Andrew Donnellan , Christophe Lombard References: <1519683513-16731-1-git-send-email-ukrishn@linux.vnet.ibm.com> <1519683719-17222-1-git-send-email-ukrishn@linux.vnet.ibm.com> From: Frederic Barrat Date: Thu, 22 Mar 2018 18:12:43 +0100 MIME-Version: 1.0 In-Reply-To: <1519683719-17222-1-git-send-email-ukrishn@linux.vnet.ibm.com> Content-Type: text/plain; charset=utf-8; format=flowed Message-Id: <5c799643-e957-79a4-8364-a444181c6f24@linux.vnet.ibm.com> List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Le 26/02/2018 à 23:21, Uma Krishnan a écrit : > Allocate a file descriptor for an adapter context when requested. In order > to allocate inodes for the file descriptors, a pseudo filesystem is created > and used. > > Signed-off-by: Uma Krishnan > Acked-by: Matthew R. Ochs > --- We've touched the subject before, and I don't have a magic solution, but it feels like something could be shared here with cxl, or maybe even other drivers? I only took a quick read of the inode allocator. Fred > drivers/scsi/cxlflash/ocxl_hw.c | 200 ++++++++++++++++++++++++++++++++++++++++ > drivers/scsi/cxlflash/ocxl_hw.h | 1 + > 2 files changed, 201 insertions(+) > > diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c > index 6472210..59e9003 100644 > --- a/drivers/scsi/cxlflash/ocxl_hw.c > +++ b/drivers/scsi/cxlflash/ocxl_hw.c > @@ -12,13 +12,144 @@ > * 2 of the License, or (at your option) any later version. > */ > > +#include > #include > +#include > +#include > > #include > > #include "backend.h" > #include "ocxl_hw.h" > > +/* > + * Pseudo-filesystem to allocate inodes. > + */ > + > +#define OCXLFLASH_FS_MAGIC 0x1697698f > + > +static int ocxlflash_fs_cnt; > +static struct vfsmount *ocxlflash_vfs_mount; > + > +static const struct dentry_operations ocxlflash_fs_dops = { > + .d_dname = simple_dname, > +}; > + > +/* > + * ocxlflash_fs_mount() - mount the pseudo-filesystem > + * @fs_type: File system type. > + * @flags: Flags for the filesystem. > + * @dev_name: Device name associated with the filesystem. > + * @data: Data pointer. > + * > + * Return: pointer to the directory entry structure > + */ > +static struct dentry *ocxlflash_fs_mount(struct file_system_type *fs_type, > + int flags, const char *dev_name, > + void *data) > +{ > + return mount_pseudo(fs_type, "ocxlflash:", NULL, &ocxlflash_fs_dops, > + OCXLFLASH_FS_MAGIC); > +} > + > +static struct file_system_type ocxlflash_fs_type = { > + .name = "ocxlflash", > + .owner = THIS_MODULE, > + .mount = ocxlflash_fs_mount, > + .kill_sb = kill_anon_super, > +}; > + > +/* > + * ocxlflash_release_mapping() - release the memory mapping > + * @ctx: Context whose mapping is to be released. > + */ > +static void ocxlflash_release_mapping(struct ocxlflash_context *ctx) > +{ > + if (ctx->mapping) > + simple_release_fs(&ocxlflash_vfs_mount, &ocxlflash_fs_cnt); > + ctx->mapping = NULL; > +} > + > +/* > + * ocxlflash_getfile() - allocate pseudo filesystem, inode, and the file > + * @dev: Generic device of the host. > + * @name: Name of the pseudo filesystem. > + * @fops: File operations. > + * @priv: Private data. > + * @flags: Flags for the file. > + * > + * Return: pointer to the file on success, ERR_PTR on failure > + */ > +static struct file *ocxlflash_getfile(struct device *dev, const char *name, > + const struct file_operations *fops, > + void *priv, int flags) > +{ > + struct qstr this; > + struct path path; > + struct file *file; > + struct inode *inode = NULL; > + int rc; > + > + if (fops->owner && !try_module_get(fops->owner)) { > + dev_err(dev, "%s: Owner does not exist\n", __func__); > + rc = -ENOENT; > + goto err1; > + } > + > + rc = simple_pin_fs(&ocxlflash_fs_type, &ocxlflash_vfs_mount, > + &ocxlflash_fs_cnt); > + if (unlikely(rc < 0)) { > + dev_err(dev, "%s: Cannot mount ocxlflash pseudofs rc=%d\n", > + __func__, rc); > + goto err2; > + } > + > + inode = alloc_anon_inode(ocxlflash_vfs_mount->mnt_sb); > + if (IS_ERR(inode)) { > + rc = PTR_ERR(inode); > + dev_err(dev, "%s: alloc_anon_inode failed rc=%d\n", > + __func__, rc); > + goto err3; > + } > + > + this.name = name; > + this.len = strlen(name); > + this.hash = 0; > + path.dentry = d_alloc_pseudo(ocxlflash_vfs_mount->mnt_sb, &this); > + if (!path.dentry) { > + dev_err(dev, "%s: d_alloc_pseudo failed\n", __func__); > + rc = -ENOMEM; > + goto err4; > + } > + > + path.mnt = mntget(ocxlflash_vfs_mount); > + d_instantiate(path.dentry, inode); > + > + file = alloc_file(&path, OPEN_FMODE(flags), fops); > + if (IS_ERR(file)) { > + rc = PTR_ERR(file); > + dev_err(dev, "%s: alloc_file failed rc=%d\n", > + __func__, rc); > + goto err5; > + } > + > + file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); > + file->private_data = priv; > +out: > + return file; > +err5: > + path_put(&path); > +err4: > + iput(inode); > +err3: > + simple_release_fs(&ocxlflash_vfs_mount, &ocxlflash_fs_cnt); > +err2: > + module_put(fops->owner); > +err1: > + file = ERR_PTR(rc); > + goto out; > +} > + > /** > * ocxlflash_set_master() - sets the context as master > * @ctx_cookie: Adapter context to set as master. > @@ -75,6 +206,7 @@ static void *ocxlflash_dev_context_init(struct pci_dev *pdev, void *afu_cookie) > > ctx->pe = rc; > ctx->master = false; > + ctx->mapping = NULL; > ctx->hw_afu = afu; > out: > return ctx; > @@ -100,6 +232,7 @@ static int ocxlflash_release_context(void *ctx_cookie) > goto out; > > idr_remove(&ctx->hw_afu->idr, ctx->pe); > + ocxlflash_release_mapping(ctx); > kfree(ctx); > out: > return rc; > @@ -262,6 +395,72 @@ static void *ocxlflash_create_afu(struct pci_dev *pdev) > goto out; > } > > +static const struct file_operations ocxl_afu_fops = { > + .owner = THIS_MODULE, > +}; > + > +/** > + * ocxlflash_get_fd() - get file descriptor for an adapter context > + * @ctx_cookie: Adapter context. > + * @fops: File operations to be associated. > + * @fd: File descriptor to be returned back. > + * > + * Return: pointer to the file on success, ERR_PTR on failure > + */ > +static struct file *ocxlflash_get_fd(void *ctx_cookie, > + struct file_operations *fops, int *fd) > +{ > + struct ocxlflash_context *ctx = ctx_cookie; > + struct device *dev = ctx->hw_afu->dev; > + struct file *file; > + int flags, fdtmp; > + int rc = 0; > + char *name = NULL; > + > + /* Only allow one fd per context */ > + if (ctx->mapping) { > + dev_err(dev, "%s: Context is already mapped to an fd\n", > + __func__); > + rc = -EEXIST; > + goto err1; > + } > + > + flags = O_RDWR | O_CLOEXEC; > + > + /* This code is similar to anon_inode_getfd() */ > + rc = get_unused_fd_flags(flags); > + if (unlikely(rc < 0)) { > + dev_err(dev, "%s: get_unused_fd_flags failed rc=%d\n", > + __func__, rc); > + goto err1; > + } > + fdtmp = rc; > + > + /* Use default ops if there is no fops */ > + if (!fops) > + fops = (struct file_operations *)&ocxl_afu_fops; > + > + name = kasprintf(GFP_KERNEL, "ocxlflash:%d", ctx->pe); > + file = ocxlflash_getfile(dev, name, fops, ctx, flags); > + kfree(name); > + if (IS_ERR(file)) { > + rc = PTR_ERR(file); > + dev_err(dev, "%s: ocxlflash_getfile failed rc=%d\n", > + __func__, rc); > + goto err2; > + } > + > + ctx->mapping = file->f_mapping; > + *fd = fdtmp; > +out: > + return file; > +err2: > + put_unused_fd(fdtmp); > +err1: > + file = ERR_PTR(rc); > + goto out; > +} > + > /* Backend ops to ocxlflash services */ > const struct cxlflash_backend_ops cxlflash_ocxl_ops = { > .module = THIS_MODULE, > @@ -271,4 +470,5 @@ const struct cxlflash_backend_ops cxlflash_ocxl_ops = { > .release_context = ocxlflash_release_context, > .create_afu = ocxlflash_create_afu, > .destroy_afu = ocxlflash_destroy_afu, > + .get_fd = ocxlflash_get_fd, > }; > diff --git a/drivers/scsi/cxlflash/ocxl_hw.h b/drivers/scsi/cxlflash/ocxl_hw.h > index 0381682..7abc532 100644 > --- a/drivers/scsi/cxlflash/ocxl_hw.h > +++ b/drivers/scsi/cxlflash/ocxl_hw.h > @@ -32,6 +32,7 @@ struct ocxl_hw_afu { > > struct ocxlflash_context { > struct ocxl_hw_afu *hw_afu; /* HW AFU back pointer */ > + struct address_space *mapping; /* Mapping for pseudo filesystem */ > bool master; /* Whether this is a master context */ > int pe; /* Process element */ > }; >