diff --git a/ChangeLog b/ChangeLog index 75cac6a4e..8c125fa97 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2011-11-05 Vladimir Serbinenko + + Support BtrFS embedding. + + * grub-core/fs/btrfs.c (grub_btrfs_embed) [GRUB_UTIL]: New function. + (grub_btrfs_fs) [GRUB_UTIL]: Set embed. + * include/grub/fs.h (grub_fs) [GRUB_UTIL]: New field embed. + * util/grub-setup.c (setup): Use fs embedding if available. + Add additional sanity check. + 2011-11-05 Vladimir Serbinenko * util/grub-install.in: Fix condition for config_opt. diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c index 16e034661..3dc680034 100644 --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c @@ -1596,6 +1596,35 @@ grub_btrfs_label (grub_device_t device, char **label) return grub_errno; } +#ifdef GRUB_UTIL +static grub_err_t +grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + unsigned int *nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors) +{ + unsigned i; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "BtrFS curently supports only PC-BIOS embedding"); + + if (64 * 2 - 1 < *nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Your core.img is unusually large. " + "It won't fit in the embedding area."); + + *nsectors = 64 * 2 - 1; + *sectors = grub_malloc (*nsectors * sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = i + 1; + + return GRUB_ERR_NONE; +} +#endif + static struct grub_fs grub_btrfs_fs = { .name = "btrfs", .dir = grub_btrfs_dir, @@ -1605,6 +1634,7 @@ static struct grub_fs grub_btrfs_fs = { .uuid = grub_btrfs_uuid, .label = grub_btrfs_label, #ifdef GRUB_UTIL + .embed = grub_btrfs_embed, .reserved_first_sector = 1, #endif }; diff --git a/include/grub/fs.h b/include/grub/fs.h index 2c39332a9..dd274e151 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -25,6 +25,10 @@ #include #include +/* For embedding types. */ +#ifdef GRUB_UTIL +#include +#endif /* Forward declaration is required, because of mutual reference. */ struct grub_file; @@ -74,6 +78,11 @@ struct grub_fs grub_err_t (*mtime) (grub_device_t device, grub_int32_t *timebuf); #ifdef GRUB_UTIL + /* Determine sectors available for embedding. */ + grub_err_t (*embed) (grub_device_t device, unsigned int *nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors); + /* Whether this filesystem reserves first sector for DOS-style boot. */ int reserved_first_sector; #endif diff --git a/util/grub-setup.c b/util/grub-setup.c index 99de26f76..d3f6fe8b8 100644 --- a/util/grub-setup.c +++ b/util/grub-setup.c @@ -408,29 +408,44 @@ setup (const char *dir, free (tmp_img); - if (! dest_partmap) + if (! dest_partmap && ! fs) { grub_util_warn (_("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea.")); goto unable_to_embed; } - if (multiple_partmaps || fs) + if (multiple_partmaps || (dest_partmap && fs)) { grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet.")); goto unable_to_embed; } - if (!dest_partmap->embed) + if (dest_partmap && !dest_partmap->embed) { grub_util_warn ("Partition style '%s' doesn't support embeding", dest_partmap->name); goto unable_to_embed; } + if (fs && !fs->embed) + { + grub_util_warn ("File system '%s' doesn't support embeding", + fs->name); + goto unable_to_embed; + } + nsec = core_sectors; - err = dest_partmap->embed (dest_dev->disk, &nsec, - GRUB_EMBED_PCBIOS, §ors); - if (nsec > 2 * core_sectors) - nsec = 2 * core_sectors; + if (dest_partmap) + err = dest_partmap->embed (dest_dev->disk, &nsec, + GRUB_EMBED_PCBIOS, §ors); + else + err = fs->embed (dest_dev, &nsec, + GRUB_EMBED_PCBIOS, §ors); + if (!err && nsec < core_sectors) + { + err = grub_error (GRUB_ERR_OUT_OF_RANGE, + "Your embedding area is unusually small. " + "core.img won't fit in it."); + } if (err) { @@ -439,6 +454,9 @@ setup (const char *dir, goto unable_to_embed; } + if (nsec > 2 * core_sectors) + nsec = 2 * core_sectors; + /* Clean out the blocklists. */ block = first_block; while (block->len)