> On Mar 22, 2018, at 12:12 PM, Frederic Barrat <fbar...@linux.vnet.ibm.com> > wrote: > > > > 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 <ukri...@linux.vnet.ibm.com> >> Acked-by: Matthew R. Ochs <mro...@linux.vnet.ibm.com> >> --- > > > 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? > Yes, perhaps we could look at refactoring in a future series.
> 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 <linux/file.h> >> #include <linux/idr.h> >> +#include <linux/module.h> >> +#include <linux/mount.h> >> #include <misc/ocxl.h> >> #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 */ >> };