int ploop_complete_running_operation(const char *device) { struct ploop_balloon_ctl b_ctl; int fd, ret; fd = open_device(device); if (fd == -1) return SYSEXIT_OPEN; bzero(&b_ctl, sizeof(b_ctl)); b_ctl.keep_intact = 1; ret = ioctl(fd, PLOOP_IOC_BALLOON, &b_ctl); if (ret) { ploop_err(errno, "Unable to get in-kernel maintenance state"); ret = SYSEXIT_DEVIOC; goto err; } if (b_ctl.mntn_type == PLOOP_MNTN_OFF) goto err; ploop_log(0, "Completing an on-going operation %s for device %s", mntn2str(b_ctl.mntn_type), device); switch (b_ctl.mntn_type) { case PLOOP_MNTN_MERGE: ret = ioctl_device(fd, PLOOP_IOC_MERGE, 0); break; case PLOOP_MNTN_GROW: ret = ioctl_device(fd, PLOOP_IOC_GROW, 0); break; case PLOOP_MNTN_RELOC: case PLOOP_MNTN_FBLOADED: ret = ploop_balloon_complete(device); break; case PLOOP_MNTN_TRACK: ret = ioctl_device(fd, PLOOP_IOC_TRACK_ABORT, 0); break; case PLOOP_MNTN_DISCARD: ret = ploop_balloon_complete(device); break; case PLOOP_MNTN_BALLOON: /* FIXME : ploop_balloon_check_and_repair(device, mount_point, 1; */ ret = 0; break; } err: close(fd); return ret; }
int ploop_balloon_complete(const char *device) { int fd, err; struct ploop_balloon_ctl b_ctl; fd = open_device(device); if (fd == -1) return SYSEXIT_OPEN; err = ioctl(fd, PLOOP_IOC_DISCARD_FINI); if (err && errno != EBUSY) { ploop_err(errno, "Can't finalize discard mode"); err = SYSEXIT_DEVIOC; goto out; } memset(&b_ctl, 0, sizeof(b_ctl)); b_ctl.keep_intact = 1; err = ioctl_device(fd, PLOOP_IOC_BALLOON, &b_ctl); if (err) goto out; switch (b_ctl.mntn_type) { case PLOOP_MNTN_BALLOON: case PLOOP_MNTN_MERGE: case PLOOP_MNTN_GROW: case PLOOP_MNTN_TRACK: case PLOOP_MNTN_OFF: ploop_log(0, "Nothing to complete: kernel is in \"%s\" state", mntn2str(b_ctl.mntn_type)); goto out; case PLOOP_MNTN_RELOC: case PLOOP_MNTN_FBLOADED: break; default: ploop_err(0, "Error: unknown mntn_type (%u)", b_ctl.mntn_type); err = SYSEXIT_PROTOCOL; goto out; } err = ploop_balloon_relocation(fd, &b_ctl, device); out: close(fd); return err; }
static int do_truncate(int fd, int mntn_type, off_t old_size, off_t new_size) { int ret; switch (mntn_type) { case PLOOP_MNTN_OFF: case PLOOP_MNTN_MERGE: case PLOOP_MNTN_GROW: case PLOOP_MNTN_TRACK: break; case PLOOP_MNTN_BALLOON: ploop_err(0, "Error: mntn_type is PLOOP_MNTN_BALLOON " "after IOC_BALLOON"); return(SYSEXIT_PROTOCOL); case PLOOP_MNTN_FBLOADED: case PLOOP_MNTN_RELOC: ploop_err(0, "Can't truncate hidden balloon before previous " "balloon operation (%s) is completed. Use \"ploop-balloon " "complete\".", mntn2str(mntn_type)); return(SYSEXIT_EBUSY); default: ploop_err(0, "Error: unknown mntn_type (%u)", mntn_type); return(SYSEXIT_PROTOCOL); } if (new_size == old_size) { ploop_log(0, "Nothing to do: new_size == old_size"); } else if (ftruncate(fd, new_size)) { ploop_err(errno, "Can't truncate hidden balloon"); fsync_balloon(fd); return(SYSEXIT_FTRUNCATE); } else { ret = fsync_balloon(fd); if (ret) return ret; ploop_log(0, "Successfully truncated balloon from %llu to %llu bytes", (unsigned long long)old_size, (unsigned long long)new_size); } return 0; }
static int pb_status(int argc, char **argv) { int i, ret; __u32 state; while ((i = getopt(argc, argv, "fd:m:")) != EOF) { switch (i) { case 'f': force = 1; break; case 'd': device = optarg; break; case 'm': mount_point = optarg; break; default: usage_status(); return SYSEXIT_PARAM; } } argc -= optind; argv += optind; GET_DD(argc, argv); if (argc != 0 || fill_opts()) { usage_status(); return SYSEXIT_PARAM; } ret = ploop_balloon_get_state(device, &state); if (ret) return ret; fprintf(stdout, "Current state of in-kernel maintenance: %s\n", mntn2str(state)); return 0; }
int ploop_balloon_clear_state(const char *device) { int fd, ret; struct ploop_balloon_ctl b_ctl; fd = open_device(device); if (fd == -1) return SYSEXIT_OPEN; bzero(&b_ctl, sizeof(b_ctl)); ret = ioctl_device(fd, PLOOP_IOC_BALLOON, &b_ctl); if (ret) goto err; if (b_ctl.mntn_type != PLOOP_MNTN_OFF) { ploop_err(0, "Can't clear stale in-kernel \"BALLOON\" " "maintenance state because kernel is in \"%s\" " "state now", mntn2str(b_ctl.mntn_type)); ret = SYSEXIT_EBUSY; } err: close(fd); return ret; }
int ploop_balloon_check_and_repair(const char *device, const char *mount_point, int repair) { int ret, fd = -1; int balloonfd = -1; __u32 n_free_blocks; __u32 freezed_a_h; __u32 dev_start; /* /sys/block/ploop0/ploop0p1/start */ struct ploop_balloon_ctl b_ctl; struct stat st; struct pfiemap *pfiemap = NULL; struct freemap *freemap = NULL; struct freemap *rangemap = NULL; struct relocmap *relocmap = NULL; struct ploop_freeblks_ctl *freeblks = NULL; struct ploop_relocblks_ctl *relocblks= NULL; char *msg = repair ? "repair" : "check"; __u32 *reverse_map = NULL; __u32 reverse_map_len; int top_level; int entries_used; struct delta delta = {}; int drop_state = 0; ret = get_balloon(mount_point, &st, &balloonfd); if (ret) return ret; if (st.st_size == 0) { ploop_log(0, "Nothing to do: hidden balloon is empty"); close(balloonfd); return 0; } pfiemap = fiemap_alloc(128); freemap = freemap_alloc(128); rangemap = freemap_alloc(128); relocmap = relocmap_alloc(128); if (!pfiemap || !freemap || !rangemap || !relocmap) { ret = SYSEXIT_MALLOC; goto err; } fd = open_device(device); if (fd == -1) { ret = SYSEXIT_OPEN; goto err; } memset(&b_ctl, 0, sizeof(b_ctl)); /* block other maintenance ops even if we only check balloon */ b_ctl.inflate = 1; ret = ioctl_device(fd, PLOOP_IOC_BALLOON, &b_ctl); if (ret) goto err; switch (b_ctl.mntn_type) { case PLOOP_MNTN_BALLOON: drop_state = 1; ret = open_top_delta(device, &delta, &top_level); if (ret) goto err; reverse_map_len = delta.l2_size + delta.l2_size; reverse_map = alloc_reverse_map(reverse_map_len); if (reverse_map == NULL) { ret = SYSEXIT_MALLOC; goto err; } break; case PLOOP_MNTN_MERGE: case PLOOP_MNTN_GROW: case PLOOP_MNTN_TRACK: ploop_err(0, "Can't %s hidden balloon while another " "maintenance operation is in progress (%s)", msg, mntn2str(b_ctl.mntn_type)); ret = SYSEXIT_EBUSY; goto err; case PLOOP_MNTN_FBLOADED: case PLOOP_MNTN_RELOC: ploop_err(0, "Can't %s hidden balloon before previous " "balloon operation (%s) is completed. Use " "\"ploop-balloon complete\".", msg, mntn2str(b_ctl.mntn_type)); ret = SYSEXIT_EBUSY; goto err; case PLOOP_MNTN_OFF: ploop_err(0, "Error: mntn_type is PLOOP_MNTN_OFF after " "IOC_BALLOON"); ret = SYSEXIT_PROTOCOL; goto err; default: ploop_err(0, "Error: unknown mntn_type (%u)", b_ctl.mntn_type); ret = SYSEXIT_PROTOCOL; goto err; } if (dev_num2dev_start(device, st.st_dev, &dev_start)) { ploop_err(0, "Can't find out offset from start of ploop " "device (%s) to start of partition where fs (%s) " "resides", device, mount_point); ret = SYSEXIT_SYSFS; goto err; } ret = fiemap_get(balloonfd, S2B(dev_start), 0, st.st_size, &pfiemap); if (ret) goto err; fiemap_adjust(pfiemap, delta.blocksize); ret = fiemap_build_rmap(pfiemap, reverse_map, reverse_map_len, &delta); if (ret) goto err; ret = rmap2freemap(reverse_map, 0, reverse_map_len, &freemap, &entries_used); if (ret) goto err; if (entries_used == 0) { ploop_log(0, "No free blocks found"); goto err; } ret = freemap2freeblks(freemap, top_level, &freeblks, &n_free_blocks); if (ret) goto err; if (!repair) { ploop_log(0, "Found %u free blocks. Consider using " "\"ploop-balloon repair\"", n_free_blocks); ret = 0; goto err; } else { ploop_log(0, "Found %u free blocks", n_free_blocks); } ret = ioctl_device(fd, PLOOP_IOC_FREEBLKS, freeblks); if (ret) goto err; drop_state = 0; freezed_a_h = freeblks->alloc_head; if (freezed_a_h > reverse_map_len) { ploop_err(0, "Image corrupted: a_h=%u > rlen=%u", freezed_a_h, reverse_map_len); ret = SYSEXIT_PLOOPFMT; goto err; } ret = range_build(freezed_a_h, n_free_blocks, reverse_map, reverse_map_len, &delta, freemap, &rangemap, &relocmap); if (ret) goto err; ret = relocmap2relocblks(relocmap, top_level, freezed_a_h, n_free_blocks, &relocblks); if (ret) goto err; ret = ioctl_device(fd, PLOOP_IOC_RELOCBLKS, relocblks); if (ret) goto err; ploop_log(0, "TRUNCATED: %u cluster-blocks (%llu bytes)", relocblks->alloc_head, (unsigned long long)(relocblks->alloc_head * S2B(delta.blocksize))); err: if (drop_state) { memset(&b_ctl, 0, sizeof(b_ctl)); (void)ioctl_device(fd, PLOOP_IOC_BALLOON, &b_ctl); } // FIXME: close_delta() if (balloonfd >= 0) close(balloonfd); if (fd >= 0) close(fd); free(pfiemap); free(freemap); free(rangemap); free(relocmap); free(reverse_map); free(freeblks); free(relocblks); return ret; }
static int do_inflate(int fd, int mntn_type, off_t old_size, off_t *new_size, int *drop_state) { struct stat st; int err; *drop_state = 0; switch (mntn_type) { case PLOOP_MNTN_BALLOON: break; case PLOOP_MNTN_MERGE: case PLOOP_MNTN_GROW: case PLOOP_MNTN_TRACK: ploop_err(0, "Can't inflate hidden balloon while another " "maintenance operation is in progress (%s)", mntn2str(mntn_type)); return(SYSEXIT_EBUSY); case PLOOP_MNTN_FBLOADED: case PLOOP_MNTN_RELOC: ploop_err(0, "Can't inflate hidden balloon before previous " "balloon operation (%s) is completed. Use " "\"ploop-balloon complete\".", mntn2str(mntn_type)); return(SYSEXIT_EBUSY); case PLOOP_MNTN_OFF: ploop_err(0, "Error: mntn_type is PLOOP_MNTN_OFF after " "IOC_BALLOON"); return(SYSEXIT_PROTOCOL); default: ploop_err(0, "Error: unknown mntn_type (%u)", mntn_type); return(SYSEXIT_PROTOCOL); } err = sys_fallocate(fd, 0, 0, *new_size); if (err) ploop_err(errno, "Can't fallocate balloon"); if (fstat(fd, &st)) { ploop_err(errno, "Can't stat balloon (2)"); if (ftruncate(fd, old_size)) ploop_err(errno, "Can't revert old_size back"); return(err ? SYSEXIT_FALLOCATE : SYSEXIT_FSTAT); } if (err) { if (st.st_size != old_size) { if (ftruncate(fd, old_size)) ploop_err(errno, "Can't revert old_size back (2)"); else *drop_state = 1; } return(SYSEXIT_FALLOCATE); } if (st.st_size < *new_size) { ploop_err(0, "Error: after fallocate(%d, 0, 0, %llu) fstat " "reported size == %llu", fd, (unsigned long long)*new_size, (unsigned long long)st.st_size); if (ftruncate(fd, old_size)) ploop_err(errno, "Can't revert old_size back (3)"); else *drop_state = 1; return(SYSEXIT_FALLOCATE); } *new_size = st.st_size; err = fsync_balloon(fd); if (err) return err; ploop_log(0, "Successfully inflated balloon from %llu to %llu bytes", (unsigned long long)old_size, (unsigned long long)*new_size); return 0; }