diff options
author | Karel Zak | 2014-10-06 13:32:43 +0200 |
---|---|---|
committer | Karel Zak | 2014-10-07 14:55:33 +0200 |
commit | 11eee4c4773842bbb960b08fef024c345ee55f1e (patch) | |
tree | 409f55550ce6979599a5929a77011e49a5d9b00a /libfdisk/src/context.c | |
parent | libfdisk: fix sun and sgi to be usable from sfdisk (diff) | |
download | kernel-qcow2-util-linux-11eee4c4773842bbb960b08fef024c345ee55f1e.tar.gz kernel-qcow2-util-linux-11eee4c4773842bbb960b08fef024c345ee55f1e.tar.xz kernel-qcow2-util-linux-11eee4c4773842bbb960b08fef024c345ee55f1e.zip |
libfdisk: propagate assign-device operation to parent
Let's make it possible to use fdisk_assign_device() for nested
contexts.
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk/src/context.c')
-rw-r--r-- | libfdisk/src/context.c | 142 |
1 files changed, 110 insertions, 32 deletions
diff --git a/libfdisk/src/context.c b/libfdisk/src/context.c index 3926c37c5..8a5397368 100644 --- a/libfdisk/src/context.c +++ b/libfdisk/src/context.c @@ -63,14 +63,65 @@ struct fdisk_context *fdisk_new_context(void) return cxt; } +static void init_nested_from_parent(struct fdisk_context *cxt, int isnew) +{ + struct fdisk_context *parent; + + assert(cxt); + assert(cxt->parent); + + parent = cxt->parent; + + cxt->dev_path = parent->dev_path; + cxt->alignment_offset = parent->alignment_offset; + cxt->ask_cb = parent->ask_cb; + cxt->ask_data = parent->ask_data; + cxt->dev_fd = parent->dev_fd; + cxt->first_lba = parent->first_lba; + cxt->firstsector_bufsz = parent->firstsector_bufsz; + cxt->firstsector = parent->firstsector; + cxt->geom = parent->geom; + cxt->grain = parent->grain; + cxt->io_size = parent->io_size; + cxt->last_lba = parent->last_lba; + cxt->min_io_size = parent->min_io_size; + cxt->optimal_io_size = parent->optimal_io_size; + cxt->phy_sector_size = parent->phy_sector_size; + cxt->readonly = parent->readonly; + cxt->script = parent->script; + fdisk_ref_script(cxt->script); + cxt->sector_size = parent->sector_size; + cxt->total_sectors = parent->total_sectors; + cxt->user_geom = parent->user_geom; + cxt->user_log_sector = parent->user_log_sector; + cxt->user_pyh_sector = parent->user_pyh_sector; + + /* parent <--> nested independent setting, initialize for new nested + * contexts only */ + if (isnew) { + cxt->listonly = parent->listonly; + cxt->display_details = parent->display_details; + cxt->display_in_cyl_units = parent->display_in_cyl_units; + } + +} + /** * fdisk_new_nested_context: * @parent: parental context * @name: optional label name (e.g. "bsd") * - * This is supported for MBR+BSD and GPT+pMBR only. + * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR). + * The function also probes for the nested label on the device if device is + * already assigned to parent. + * + * The new context is initialized according to @parent and both context shares + * some settings and file descriptor to the device. The child propagate some + * changes (like fdisk_assign_device()) to parent, but it does not work + * vice-versa. The behavior is undefined if you assign another device to + * parent. * - * Returns: new context for nested partiton table. + * Returns: new context for nested partition table. */ struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, const char *name) @@ -85,25 +136,12 @@ struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, return NULL; DBG(CXT, ul_debugobj(parent, "alloc nested [%p]", cxt)); - cxt->dev_fd = parent->dev_fd; cxt->refcount = 1; - cxt->parent = parent; - - cxt->io_size = parent->io_size; - cxt->optimal_io_size = parent->optimal_io_size; - cxt->min_io_size = parent->min_io_size; - cxt->phy_sector_size = parent->phy_sector_size; - cxt->sector_size = parent->sector_size; - cxt->alignment_offset = parent->alignment_offset; - cxt->grain = parent->grain; - cxt->first_lba = parent->first_lba; - cxt->total_sectors = parent->total_sectors; - cxt->firstsector = parent->firstsector; - cxt->ask_cb = parent->ask_cb; - cxt->ask_data = parent->ask_data; + fdisk_ref_context(parent); + cxt->parent = parent; - cxt->geom = parent->geom; + init_nested_from_parent(cxt, 1); if (name) { if (strcmp(name, "bsd") == 0) @@ -112,7 +150,7 @@ struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt); } - if (lb) { + if (lb && parent->dev_fd >= 0) { DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name)); cxt->label = lb; @@ -312,25 +350,29 @@ static void reset_context(struct fdisk_context *cxt) for (i = 0; i < cxt->nlabels; i++) fdisk_deinit_label(cxt->labels[i]); - /* free device specific stuff */ - if (!cxt->parent && cxt->dev_fd > -1) - close(cxt->dev_fd); - free(cxt->dev_path); - - if (cxt->parent == NULL || cxt->parent->firstsector != cxt->firstsector) + if (cxt->parent) { + /* the first sector may be independent on parent */ + if (cxt->parent->firstsector != cxt->firstsector) + free(cxt->firstsector); + } else { + /* we close device only in primary context */ + if (cxt->dev_fd > -1) + close(cxt->dev_fd); + free(cxt->dev_path); free(cxt->firstsector); + } - /* initialize */ cxt->dev_fd = -1; cxt->dev_path = NULL; cxt->firstsector = NULL; cxt->firstsector_bufsz = 0; fdisk_zeroize_device_properties(cxt); + fdisk_unref_script(cxt->script); + cxt->script = NULL; cxt->label = NULL; - cxt->script = NULL; } /* @@ -388,13 +430,18 @@ static int warn_wipe(struct fdisk_context *cxt) /** * fdisk_assign_device: + * @cxt: context * @fname: path to the device to be handled * @readonly: how to open the device * - * Open the device, discovery topology, geometry, detect disklabel and - * switch the current label driver to reflect the probing result. + * Open the device, discovery topology, geometry, detect disklabel and switch + * the current label driver to reflect the probing result. * - * Note that this function resets all generic setting in context. + * Note that this function resets all generic setting in context. If the @cxt + * is nested context then the device is assigned to the parental context and + * necessary properties are copied to the @cxt. The change is propagated in + * child->parent direction only. It's impossible to use a different device for + * primary and nested contexts. * * Returns: 0 on success, < 0 on error. */ @@ -406,6 +453,24 @@ int fdisk_assign_device(struct fdisk_context *cxt, DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname)); assert(cxt); + /* redirect request to parent */ + if (cxt->parent) { + int rc, org = fdisk_is_listonly(cxt->parent); + + /* assign_device() is sensitive to "listonly" mode, so let's + * follow the current context setting for the parent to avoid + * unwanted extra warnings. */ + fdisk_enable_listonly(cxt->parent, fdisk_is_listonly(cxt)); + + rc = fdisk_assign_device(cxt->parent, fname, readonly); + fdisk_enable_listonly(cxt->parent, org); + + init_nested_from_parent(cxt, 0); + if (!rc) + fdisk_probe_labels(cxt); + return rc; + } + reset_context(cxt); fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC); @@ -450,13 +515,21 @@ fail: * @cxt: context * @nosync: disable fsync() * - * Close device and call fsync() + * Close device and call fsync(). If the @cxt is nested context than the + * request is redirected to the parent. */ int fdisk_deassign_device(struct fdisk_context *cxt, int nosync) { assert(cxt); assert(cxt->dev_fd >= 0); + if (cxt->parent) { + int rc = fdisk_deassign_device(cxt->parent, nosync); + + init_nested_from_parent(cxt, 0); + return rc; + } + if (cxt->readonly) close(cxt->dev_fd); else { @@ -508,7 +581,8 @@ void fdisk_unref_context(struct fdisk_context *cxt) cxt->refcount--; if (cxt->refcount <= 0) { DBG(CXT, ul_debugobj(cxt, "freeing context %p for %s", cxt, cxt->dev_path)); - reset_context(cxt); + + reset_context(cxt); /* this is sensitive to parent<->child relationship! */ /* deallocate label's private stuff */ for (i = 0; i < cxt->nlabels; i++) { @@ -519,6 +593,10 @@ void fdisk_unref_context(struct fdisk_context *cxt) else free(cxt->labels[i]); } + + fdisk_unref_context(cxt->parent); + cxt->parent = NULL; + free(cxt); } } |