This patch introducces the idea of envblk functions to GRUB. These functions are used to interact with a grubenv file stored not in the usual grub tree, but instead in a special filesystem-managed region that can more easily be accessed at boot time. These functions interface between calling code and the per-fs logic, an interface for which is also added as part of this patch.
Signed-off-by: Paul Dagnelie <p...@delphix.com> --- grub-core/kern/file.c | 30 ++++++++++++++++++++++++++++-- include/grub/file.h | 10 ++++++++++ include/grub/fs.h | 12 ++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c index 75eb5e2fa..f929f61a0 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c @@ -149,6 +149,27 @@ grub_file_open (const char *name, enum grub_file_type type) return 0; } +grub_file_t +grub_file_envblk_open (grub_fs_t fs, grub_device_t device, enum grub_file_type type) +{ + grub_file_t file = NULL; + file = (grub_file_t) grub_zalloc (sizeof (*file)); + if (! file) + return NULL; + file->device = device; + file->special = 1; + + if ((fs->fs_envblk_open) (file) != GRUB_ERR_NONE) { + grub_free(file); + return NULL; + } + + file->fs = fs; + grub_errno = GRUB_ERR_NONE; + + return grub_apply_file_filters(file, type, NULL); +} + grub_disk_read_hook_t grub_file_progress_hook; grub_ssize_t @@ -185,7 +206,10 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) file->read_hook_data = file; file->progress_offset = file->offset; } - res = (file->fs->fs_read) (file, buf, len); + if (grub_file_envblk (file)) + res = (file->fs->fs_envblk_read) (file, buf, len); + else + res = (file->fs->fs_read) (file, buf, len); file->read_hook = read_hook; file->read_hook_data = read_hook_data; if (res > 0) @@ -197,7 +221,9 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) grub_err_t grub_file_close (grub_file_t file) { - if (file->fs->fs_close) + if (grub_file_envblk (file) && file->fs->fs_envblk_close) + (file->fs->fs_envblk_close) (file); + else if (file->fs->fs_close) (file->fs->fs_close) (file); if (file->device) diff --git a/include/grub/file.h b/include/grub/file.h index 31567483c..1cc688f55 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -170,6 +170,9 @@ struct grub_file /* Caller-specific data passed to the read hook. */ void *read_hook_data; + + /* If the file is an FS's special file, which uses separate functions for interaction. */ + int special; }; typedef struct grub_file *grub_file_t; @@ -211,6 +214,7 @@ grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf, grub_size_t len); grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset); grub_err_t EXPORT_FUNC(grub_file_close) (grub_file_t file); +grub_file_t EXPORT_FUNC(grub_file_envblk_open) (grub_fs_t fs, grub_device_t device, enum grub_file_type type); /* Return value of grub_file_size() in case file size is unknown. */ #define GRUB_FILE_SIZE_UNKNOWN 0xffffffffffffffffULL @@ -233,6 +237,12 @@ grub_file_seekable (const grub_file_t file) return !file->not_easily_seekable; } +static inline int +grub_file_envblk (const grub_file_t file) +{ + return file->special; +} + grub_file_t grub_file_offset_open (grub_file_t parent, enum grub_file_type type, grub_off_t start, grub_off_t size); diff --git a/include/grub/fs.h b/include/grub/fs.h index 302e48d4b..ec1a7a50e 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -96,6 +96,18 @@ struct grub_fs /* Whether blocklist installs have a chance to work. */ int blocklist_install; #endif + + /* + * The envblk functions are defined on filesystems that need to handle + * grub-writable files in a special way. This is most commonly the case for + * CoW filesystems like btrfs and ZFS. The normal read and close functions + * should detect that they are being called on a special file and act + * appropriately. + */ + grub_err_t (*fs_envblk_open) (struct grub_file *file); + grub_ssize_t (*fs_envblk_read) (struct grub_file *file, char *buf, grub_size_t len); + grub_err_t (*fs_envblk_write) (struct grub_file *file, char *buf, grub_size_t len); + grub_err_t (*fs_envblk_close) (struct grub_file *file); }; typedef struct grub_fs *grub_fs_t; -- 2.19.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel