From acc930f1e9c482dc826bb63a6b9d36463a280210 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 18 Jun 2015 08:45:11 +0200 Subject: Add globalvar_add_simple_string function This adds a globalvar string function to pass a pointer to a string. With this we can directly access the string to get the variable and don't have to getenv() the string first. Signed-off-by: Sascha Hauer --- include/globalvar.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/globalvar.h b/include/globalvar.h index 8b2caf1f8b..6e10956b89 100644 --- a/include/globalvar.h +++ b/include/globalvar.h @@ -17,6 +17,20 @@ int globalvar_add(const char *name, char *globalvar_get_match(const char *match, const char *separator); void globalvar_set_match(const char *match, const char *val); +static inline int globalvar_add_simple_string(const char *name, + char **value) +{ + struct param_d *p; + + p = dev_add_param_string(&global_device, name, NULL, NULL, + value, NULL); + + if (IS_ERR(p)) + return PTR_ERR(p); + + return 0; +} + static inline int globalvar_add_simple_int(const char *name, int *value, const char *format) { @@ -85,6 +99,11 @@ static inline int globalvar_add_simple(const char *name, const char *value) return 0; } +static inline int globalvar_add_simple_string(const char *name, char **value) +{ + return 0; +} + static inline int globalvar_add_simple_int(const char *name, int *value, const char *format) { -- cgit v1.2.3 From bc31d85c6e23d724664e76bcfc3b2eda778012a3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jun 2015 12:40:04 +0200 Subject: cdev: Add partuuid string to struct cdev This adds the partuuid string to struct cdev in order to have this available for constructing a suitable Linux root=PARTUUID= option for booting Linux. Signed-off-by: Sascha Hauer --- common/partitions.c | 1 + common/partitions/dos.c | 4 ++++ common/partitions/parser.h | 1 + include/driver.h | 3 +++ 4 files changed, 9 insertions(+) diff --git a/common/partitions.c b/common/partitions.c index 37d9cb7edc..4f50bfeff1 100644 --- a/common/partitions.c +++ b/common/partitions.c @@ -64,6 +64,7 @@ static int register_one_partition(struct block_device *blk, } cdev->dos_partition_type = part->dos_partition_type; + strcpy(cdev->partuuid, part->partuuid); free(partition_name); diff --git a/common/partitions/dos.c b/common/partitions/dos.c index 37addfd2ef..e0cb35627d 100644 --- a/common/partitions/dos.c +++ b/common/partitions/dos.c @@ -185,6 +185,7 @@ static void dos_partition(void *buf, struct block_device *blk, uint8_t *buffer = buf; int i; struct disk_signature_priv *dsp; + uint32_t signature = get_unaligned_le32(buf + 0x1b8); table = (struct partition_entry *)&buffer[446]; @@ -202,6 +203,9 @@ static void dos_partition(void *buf, struct block_device *blk, pd->parts[n].first_sec = pentry.first_sec; pd->parts[n].size = pentry.size; pd->parts[n].dos_partition_type = pentry.dos_partition_type; + if (signature) + sprintf(pd->parts[n].partuuid, "%08x-%02d", + signature, i + 1); pd->used_entries++; /* * Partitions of type 0x05 and 0x0f (and some more) diff --git a/common/partitions/parser.h b/common/partitions/parser.h index 8d39452378..8ad134a9aa 100644 --- a/common/partitions/parser.h +++ b/common/partitions/parser.h @@ -17,6 +17,7 @@ struct partition { char name[MAX_PARTITION_NAME]; u8 dos_partition_type; + char partuuid[MAX_PARTUUID_STR]; uint64_t first_sec; uint64_t size; }; diff --git a/include/driver.h b/include/driver.h index d0cdcc9715..9c6005454c 100644 --- a/include/driver.h +++ b/include/driver.h @@ -435,6 +435,8 @@ struct file_operations { int (*memmap)(struct cdev*, void **map, int flags); }; +#define MAX_PARTUUID_STR sizeof("00112233-4455-6677-8899-AABBCCDDEEFF") + struct cdev { struct file_operations *ops; void *priv; @@ -445,6 +447,7 @@ struct cdev { char *partname; /* the partition name, usually the above without the * device part, i.e. name = "nand0.barebox" -> partname = "barebox" */ + char partuuid[MAX_PARTUUID_STR]; loff_t offset; loff_t size; unsigned int flags; -- cgit v1.2.3 From e9db2079a55162821e4566efdef5b3d3b5028e88 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jun 2015 12:57:42 +0200 Subject: fs: Add device parameter for Linux root= option When registering a filesystem device add a device parameter suitable for the Linux root= option to boot from exactly this filesystem. Currently the fs layer sets this parameter to the root=PARTUUID= mechanism if a partuuid is available. Other filesystems like NFS and UBIFS which do not have a PARTUUID can overwrite this. Signed-off-by: Sascha Hauer --- fs/fs.c | 37 +++++++++++++++++++++++++++++++++++++ include/fs.h | 4 ++++ 2 files changed, 41 insertions(+) diff --git a/fs/fs.c b/fs/fs.c index c249f843bf..67c78cd111 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -1298,6 +1298,12 @@ int mount(const char *device, const char *fsname, const char *_path, goto err_no_driver; } + if (!fsdev->linux_rootarg && fsdev->cdev && fsdev->cdev->partuuid[0] != 0) { + char *str = asprintf("root=PARTUUID=%s", fsdev->cdev->partuuid); + + fsdev_set_linux_rootarg(fsdev, str); + } + return 0; err_no_driver: @@ -1708,3 +1714,34 @@ void mount_all(void) cdev_mount_default(cdev, NULL); } } + +void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str) +{ + fsdev->linux_rootarg = xstrdup(str); + + dev_add_param_fixed(&fsdev->dev, "linux.bootargs", fsdev->linux_rootarg); +} + +/** + * path_get_linux_rootarg() - Given a path return a suitable root= option for + * Linux + * @path: The path + * + * Return: A string containing the root= option or an ERR_PTR. the returned + * string must be freed by the caller. + */ +char *path_get_linux_rootarg(const char *path) +{ + struct fs_device_d *fsdev; + const char *str; + + fsdev = get_fsdevice_by_path(path); + if (!fsdev) + return ERR_PTR(-EINVAL); + + str = dev_get_param(&fsdev->dev, "linux.bootargs"); + if (!str) + return ERR_PTR(-ENOSYS); + + return xstrdup(str); +} diff --git a/include/fs.h b/include/fs.h index f95464de6a..ee7e48b0f9 100644 --- a/include/fs.h +++ b/include/fs.h @@ -100,6 +100,7 @@ struct fs_device_d { struct device_d *parent_device; struct list_head list; char *options; + char *linux_rootarg; }; #define drv_to_fs_driver(d) container_of(d, struct fs_driver_d, drv) @@ -189,4 +190,7 @@ const char *cdev_get_mount_path(struct cdev *cdev); const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions); void mount_all(void); +void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str); +char *path_get_linux_rootarg(const char *path); + #endif /* __FS_H */ -- cgit v1.2.3 From 745594d51afa71b01bb5bfda969da19aa079d214 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jun 2015 13:00:00 +0200 Subject: fs: ubifs: Implement Linux rootarg Add the parameter to boot from ubifs fileystems. This assumes that there will be only one UBI device registered in the kernel, otherwise there is no way to predict the ubi number. Signed-off-by: Sascha Hauer --- drivers/mtd/ubi/kapi.c | 1 + fs/ubifs/ubifs.c | 23 +++++++++++++++++++++++ include/linux/mtd/ubi.h | 1 + 3 files changed, 25 insertions(+) diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 08cb8dd7e0..7fc1aa8d70 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -36,6 +36,7 @@ void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di) di->min_io_size = ubi->min_io_size; di->max_write_size = ubi->max_write_size; di->ro_mode = ubi->ro_mode; + di->mtd = ubi->mtd; } EXPORT_SYMBOL_GPL(ubi_do_get_device_info); diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c index 68d90b36e7..a9189f76b5 100644 --- a/fs/ubifs/ubifs.c +++ b/fs/ubifs/ubifs.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "ubifs.h" @@ -584,6 +585,26 @@ static int ubifs_readlink(struct device_d *dev, const char *pathname, char *buf, return 0; } +static void ubifs_set_rootarg(struct ubifs_priv *priv, struct fs_device_d *fsdev) +{ + struct ubi_volume_info vi = {}; + struct ubi_device_info di = {}; + struct mtd_info *mtd; + char *str; + + ubi_get_volume_info(priv->ubi, &vi); + ubi_get_device_info(vi.ubi_num, &di); + + mtd = di.mtd; + + str = asprintf("root=ubi0:%s ubi.mtd=%s rootfstype=ubifs", + vi.name, mtd->cdev.partname); + + fsdev_set_linux_rootarg(fsdev, str); + + free(str); +} + static int ubifs_probe(struct device_d *dev) { struct fs_device_d *fsdev = dev_to_fs_device(dev); @@ -612,6 +633,8 @@ static int ubifs_probe(struct device_d *dev) goto err; } + ubifs_set_rootarg(priv, fsdev); + return 0; err: ubi_close_volume(priv->ubi); diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h index 274ec4ee41..0614681d73 100644 --- a/include/linux/mtd/ubi.h +++ b/include/linux/mtd/ubi.h @@ -154,6 +154,7 @@ struct ubi_device_info { int max_write_size; int ro_mode; dev_t cdev; + struct mtd_info *mtd; }; /* -- cgit v1.2.3 From 278d9b8ba6673e34b7ceb41212cf3e270a04d683 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jun 2015 13:00:10 +0200 Subject: fs: nfs: Implement Linux rootarg Add the root= parameter for NFS filesystems. We currently hardcode v3 and tcp which probably needs to become configurable at some point. Signed-off-by: Sascha Hauer --- Documentation/filesystems/nfs.rst | 13 +++++++++++++ fs/nfs.c | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/Documentation/filesystems/nfs.rst b/Documentation/filesystems/nfs.rst index f4eda5d13c..4469ac1dff 100644 --- a/Documentation/filesystems/nfs.rst +++ b/Documentation/filesystems/nfs.rst @@ -10,3 +10,16 @@ barebox has readonly support for NFSv3 in UDP mode. Example:: mount -t nfs 192.168.23.4:/home/user/nfsroot /mnt/nfs + +The barebox NFS driver adds a ``linux.bootargs`` device parameter to the NFS device. +This parameter holds a Linux kernel commandline snippet containing a suitable root= +option for booting from exactly that NFS share. + +Example:: + + devinfo nfs0 + ... + linux.bootargs: root=/dev/nfs nfsroot=192.168.23.4:/home/sha/nfsroot/generic-v7,v3,tcp + +The options default to ``v3,tcp`` but can be adjusted before mounting the NFS share with +the ``global.linux.rootnfsopts`` variable diff --git a/fs/nfs.c b/fs/nfs.c index 2738c781d7..5bff54a4dd 100644 --- a/fs/nfs.c +++ b/fs/nfs.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "parseopt.h" @@ -1306,6 +1307,23 @@ static int nfs_stat(struct device_d *dev, const char *filename, struct stat *s) } } +static char *rootnfsopts; + +static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device_d *fsdev) +{ + char *str; + const char *ip; + + ip = ip_to_string(npriv->server); + str = asprintf("root=/dev/nfs nfsroot=%s:%s%s%s", + ip, npriv->path, rootnfsopts[0] ? "," : "", + rootnfsopts); + + fsdev_set_linux_rootarg(fsdev, str); + + free(str); +} + static int nfs_probe(struct device_d *dev) { struct fs_device_d *fsdev = dev_to_fs_device(dev); @@ -1369,6 +1387,8 @@ static int nfs_probe(struct device_d *dev) goto err2; } + nfs_set_rootarg(npriv, fsdev); + free(tmp); return 0; @@ -1421,6 +1441,10 @@ static struct fs_driver_d nfs_driver = { static int nfs_init(void) { + rootnfsopts = xstrdup("v3,tcp"); + + globalvar_add_simple_string("linux.rootnfsopts", &rootnfsopts); + return register_fs_driver(&nfs_driver); } coredevice_initcall(nfs_init); -- cgit v1.2.3 From 716fdbf18ca12feb81e26df729a5b8969e394e96 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Jun 2015 13:00:36 +0200 Subject: blspec: Automatically append rootarg This patch makes it possible to automatically add a suitable root= option for booting Linux from the same filesystem on which the bootspec entry has been found. This adds an additional 'linux-appendroot' option to bootspec which if set to 'true' will cause barebox to automatically add a root= option. This currently works for NFS, UBIFS and regular block devices like ATA, SD/MMC using the root=PARTUUID= mechanism. Signed-off-by: Sascha Hauer --- Documentation/user/booting-linux.rst | 7 +++++++ common/blspec.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Documentation/user/booting-linux.rst b/Documentation/user/booting-linux.rst index 6e7d1550bf..39084e5afe 100644 --- a/Documentation/user/booting-linux.rst +++ b/Documentation/user/booting-linux.rst @@ -205,6 +205,13 @@ compatible NFS URI string must be passed to the boot command: boot nfs://nfshost//path/ +Additionally to the options defined in the original spec barebox understands the +``linux-appendroot`` option. This is a boolean value and if set to ``true`` barebox +will automatically append a ``root=`` string to the Linux commandline based on the +device where the entry is found on. This makes it possible to use the same rootfs +image on different devices without having to specify a different root= option each +time. + Network boot ------------ diff --git a/common/blspec.c b/common/blspec.c index 3506388eb5..742065ea63 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -601,6 +601,29 @@ int blspec_scan_devicename(struct blspec *blspec, const char *devname) return blspec_scan_device(blspec, dev); } +static int blspec_append_root(struct blspec_entry *entry) +{ + const char *appendroot; + char *rootarg; + + appendroot = blspec_entry_var_get(entry, "linux-appendroot"); + if (!appendroot || strcmp(appendroot, "true")) + return 0; + + rootarg = path_get_linux_rootarg(entry->rootpath); + if (IS_ERR(rootarg)) { + pr_err("Getting root argument for %s failed with: %s\n", + entry->rootpath, strerror(-PTR_ERR(rootarg))); + return PTR_ERR(rootarg); + } + + globalvar_add_simple("linux.bootargs.dyn.blspec.appendroot", rootarg); + + free(rootarg); + + return 0; +} + /* * blspec_boot - boot an entry * @@ -650,6 +673,10 @@ int blspec_boot(struct blspec_entry *entry, int verbose, int dryrun) globalvar_add_simple("linux.bootargs.dyn.blspec", options); + ret = blspec_append_root(entry); + if (ret) + goto err_out; + pr_info("booting %s from %s\n", blspec_entry_var_get(entry, "title"), entry->cdev ? dev_name(entry->cdev->dev) : "none"); @@ -668,7 +695,7 @@ int blspec_boot(struct blspec_entry *entry, int verbose, int dryrun) ret = bootm_boot(&data); if (ret) pr_err("Booting failed\n"); - +err_out: free((char *)data.oftree_file); free((char *)data.initrd_file); free((char *)data.os_file); -- cgit v1.2.3