diff options
Diffstat (limited to 'tools/libfsimage/zfs/fsi_zfs.c')
-rw-r--r-- | tools/libfsimage/zfs/fsi_zfs.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/tools/libfsimage/zfs/fsi_zfs.c b/tools/libfsimage/zfs/fsi_zfs.c new file mode 100644 index 0000000000..05148bcdb9 --- /dev/null +++ b/tools/libfsimage/zfs/fsi_zfs.c @@ -0,0 +1,158 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifdef FSYS_ZFS + +#include <fsimage_grub.h> +#include <fsimage_priv.h> +#include <stdio.h> +#include <inttypes.h> +#include "mb_info.h" + + +#undef filemax +#undef filepos +#undef errnum + + +#define MAXNAMELEN 256 +#define MAXPATHLEN 1024 + +/**** START FROM disk_io.c ****/ +char current_rootpool[MAXNAMELEN]; +char current_bootfs[MAXNAMELEN]; +uint64_t current_bootfs_obj; +char current_bootpath[MAXPATHLEN]; +char current_devid[MAXPATHLEN]; +int is_zfs_mount; +unsigned long best_drive; +unsigned long best_part; +int find_best_root; +unsigned long part_length; +/**** END FROM disk_io.c ****/ + +uint64_t filemax; +uint64_t filepos; + +struct multiboot_info mbi; +fsi_file_t *zfs_ffi; +int errnum; +char *bootstring = NULL; + +extern int zfs_mount(void); +extern int zfs_open(char *filename); +extern int zfs_read(char *buf, int len); + +#define ZFS_SCRATCH_SIZE 0x400000 +#define FSI_MOS_SHIFT 10 +#define FSI_MOS_MASK ((1 << FSI_MOS_SHIFT) - 1) +unsigned char fsi_mos_buf[ZFS_SCRATCH_SIZE + FSI_MOS_MASK + 1]; + +#define FSI_MOS_ALIGN(addr) (((uintptr_t)addr + FSI_MOS_MASK) & \ + ~FSI_MOS_MASK) +#define FSI_MOS(buf) ((FSI_MOS_ALIGN(buf) + \ + ZFS_SCRATCH_SIZE - 0x100000) >> FSI_MOS_SHIFT) + +static int +fsi_zfs_mount(fsi_file_t *ffi, const char *options) +{ + zfs_ffi = ffi; + mbi.mem_upper = FSI_MOS(fsi_mos_buf); + + /* If an boot filesystem is passed in, set it to current_bootfs */ + if (options != NULL) { + if (strlen(options) < MAXNAMELEN) { + strcpy(current_bootfs, options); + } + } + + return (zfs_mount()); +} + +static int +fsi_zfs_open(fsi_file_t *ffi, char *filename) +{ + char *fsi_bootstring; + uint64_t *fmax; + uint64_t *fpos; + int rc; + + zfs_ffi = ffi; + fmax = fsig_filemax(ffi); + fpos = fsig_filepos(ffi); + + rc = zfs_open(filename); + if (rc != 1) { + return (rc); + } + + *fmax = filemax; + *fpos = filepos; + + if (bootstring == NULL) { + rc = asprintf(&bootstring, + "zfs-bootfs=%s/%"PRIu64",bootpath='%s'", + current_rootpool, current_bootfs_obj, + current_bootpath); + if (rc == -1) { + return (rc); + } + fsi_bootstring = fsi_bootstring_alloc(ffi->ff_fsi, + strlen(bootstring) + 1); + strcpy(fsi_bootstring, bootstring); + } + + return (rc); +} + +static int +fsi_zfs_read(fsi_file_t *ffi, char *buf, int len) +{ + uint64_t *fpos; + int rc; + + zfs_ffi = ffi; + fpos = fsig_filepos(ffi); + filepos = *fpos; + rc = zfs_read(buf, len); + *fpos = filepos; + + return (rc); +} + + +fsi_plugin_ops_t * +fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name) +{ + static fsig_plugin_ops_t ops = { + FSIMAGE_PLUGIN_VERSION, + .fpo_mount = fsi_zfs_mount, + .fpo_dir = fsi_zfs_open, + .fpo_read = fsi_zfs_read, + }; + + *name = "zfs"; + return (fsig_init(fp, &ops)); +} + +#endif /* FSYS_ZFS */ |