static int pb_complete(int argc, char **argv) { int i, ret, fd; while ((i = getopt(argc, argv, "d:m:")) != EOF) { switch (i) { case 'd': device = optarg; break; case 'm': mount_point = optarg; break; default: usage_complete(); return SYSEXIT_PARAM; } } argc -= optind; argv += optind; GET_DD(argc, argv); if (argc != 0 || fill_opts()) { usage_complete(); return SYSEXIT_PARAM; } ret = get_balloon(mount_point, NULL, &fd); if (ret) return ret; return ploop_balloon_complete(device); }
static int pb_change(int argc, char **argv) { int fd; int i, ret; off_t new_size = 0; int new_size_set = 0; while ((i = getopt(argc, argv, "s:d:m:")) != EOF) { switch (i) { case 's': /* NB: currently, new_size is in 'sector' units */ if (parse_size(optarg, &new_size, "-s")) { usage_change(); return SYSEXIT_PARAM; } new_size_set++; break; case 'd': device = optarg; break; case 'm': mount_point = optarg; break; default: usage_change(); return SYSEXIT_PARAM; } } argc -= optind; argv += optind; GET_DD(argc, argv); if (argc != 0 || !new_size_set || fill_opts()) { usage_change(); return SYSEXIT_PARAM; } ret = get_balloon(mount_point, NULL, &fd); if (ret) return ret; return ploop_balloon_change_size(device, fd, new_size); }
int ploop_discard_get_stat_by_dev(const char *device, const char *mount_point, struct ploop_discard_stat *pd_stat) { int err; struct statfs stfs; struct stat st, balloon_stat; off_t ploop_size; char image[PATH_MAX]; err = get_balloon(mount_point, &balloon_stat, NULL); if (err) return err; err = statfs(mount_point, &stfs); if (err == -1) { ploop_err(errno, "statfs(%s) failed", mount_point); return 1; } err = ploop_get_size(device, &ploop_size); if (err) return 1; err = ploop_find_top_delta_name_and_format(device, image, sizeof(image), NULL, 0); if (err) return 1; err = stat(image, &st); if (err == -1) { ploop_err(errno, "stat(%s) failed", image); return 1; } pd_stat->ploop_size = S2B(ploop_size) - balloon_stat.st_size; pd_stat->image_size = st.st_size; pd_stat->data_size = pd_stat->ploop_size - stfs.f_bfree * stfs.f_bsize; pd_stat->balloon_size = balloon_stat.st_size; return 0; }
static int pb_clear(int argc, char **argv) { int i, ret; int fd2; while ((i = getopt(argc, argv, "d:m:")) != EOF) { switch (i) { case 'd': device = optarg; break; case 'm': mount_point = optarg; break; default: usage_clear(); return SYSEXIT_PARAM; } } argc -= optind; argv += optind; GET_DD(argc, argv); if (argc != 0 || fill_opts()) { usage_clear(); return SYSEXIT_PARAM; } ret = get_balloon(mount_point, NULL, &fd2); if (ret) return ret; ret = ploop_balloon_clear_state(device); if (ret) return ret; fprintf(stdout, "Current state of in-kernel maintenance is OFF now\n"); return 0; }
static int pb_show(int argc, char **argv) { int i, ret; struct stat st; 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_show(); return SYSEXIT_PARAM; } } argc -= optind; argv += optind; GET_DD(argc, argv); if (argc != 0 || fill_opts()) { usage_show(); return SYSEXIT_PARAM; } ret = get_balloon(mount_point, &st, NULL); if (ret) return ret; fprintf(stdout, "Current size of hidden balloon is %llu bytes\n", (unsigned long long) st.st_size); return 0; }
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; }