Add the drm_gem_shmem_helper_huge_mnt_create() and drm_gem_shmem_helper_huge_mnt_free() helpers to avoid code duplication in the i915 and v3d drivers (and soon panfrost/panthor). Signed-off-by: Loïc Molinari --- drivers/gpu/drm/drm_gem_shmem_helper.c | 56 ++++++++++++++++++++++++++ include/drm/drm_gem_shmem_helper.h | 14 +++++++ 2 files changed, 70 insertions(+) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 22c4b09e10a3..808721b8be3e 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include #include #include @@ -36,6 +38,60 @@ MODULE_IMPORT_NS("DMA_BUF"); * drm_gem_shmem_vmap()). These helpers perform the necessary type conversion. */ +static int drm_gem_shmem_add_fc_param(struct fs_context *fc, const char *key, + const char *value) +{ + return vfs_parse_fs_string(fc, key, value, strlen(value)); +} + +/** + * drm_gem_shmem_huge_mnt_create - Create a huge tmpfs mountpoint + * @value: huge tmpfs mount option value + * + * This function creates and mounts an internal huge tmpfs mountpoint for use + * with the drm_gem_shmem_create_with_mnt() function. + * + * The most common option value is "within_size" which only allocates huge pages + * if the page will be fully within the GEM object size. "always", "advise" and + * "never" are supported too but the latter would just create a mountpoint + * similar to default "shm_mnt" one. See shmemfs and Transparent Hugepage for + * more information. + * + * Returns: + * A struct vfsmount * on success or an ERR_PTR()-encoded negative error code on + * failure. + */ +struct vfsmount *drm_gem_shmem_huge_mnt_create(const char *value) +{ + struct file_system_type *type; + struct fs_context *fc; + struct vfsmount *mnt; + int ret; + + if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) + return ERR_PTR(-EOPNOTSUPP); + + type = get_fs_type("tmpfs"); + if (!type) + return ERR_PTR(-EOPNOTSUPP); + + fc = fs_context_for_mount(type, SB_KERNMOUNT); + if (IS_ERR(fc)) + return ERR_CAST(fc); + ret = drm_gem_shmem_add_fc_param(fc, "source", "tmpfs"); + if (ret) + return ERR_PTR(-ENOPARAM); + ret = drm_gem_shmem_add_fc_param(fc, "huge", value); + if (ret) + return ERR_PTR(-ENOPARAM); + + mnt = fc_mount_longterm(fc); + put_fs_context(fc); + + return mnt; +} +EXPORT_SYMBOL_GPL(drm_gem_shmem_huge_mnt_create); + static const struct drm_gem_object_funcs drm_gem_shmem_funcs = { .free = drm_gem_shmem_object_free, .print_info = drm_gem_shmem_object_print_info, diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h index 589f7bfe7506..5e153fb63f38 100644 --- a/include/drm/drm_gem_shmem_helper.h +++ b/include/drm/drm_gem_shmem_helper.h @@ -107,6 +107,20 @@ struct drm_gem_shmem_object { #define to_drm_gem_shmem_obj(obj) \ container_of(obj, struct drm_gem_shmem_object, base) +struct vfsmount *drm_gem_shmem_huge_mnt_create(const char *value); + +/** + * drm_gem_shmem_huge_mnt_free - Release a huge tmpfs mountpoint. + * @mnt: struct vfsmount * to release + * + * This function unmounts and releases an internal huge tmpfs mountpoint. If + * @mnt is NULL, no operation is performed. + */ +static inline void drm_gem_shmem_huge_mnt_free(struct vfsmount *mnt) +{ + kern_unmount(mnt); +} + int drm_gem_shmem_init(struct drm_device *dev, struct drm_gem_shmem_object *shmem, size_t size); struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size); struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev, -- 2.47.3