btrfs-progs: subvol: change set-default to also accept path
[platform/upstream/btrfs-progs.git] / cmds-subvolume.c
index 8b24de3..dc626a6 100644 (file)
@@ -263,6 +263,9 @@ static int cmd_subvol_delete(int argc, char **argv)
        DIR     *dirstream = NULL;
        int verbose = 0;
        int commit_mode = 0;
+       u8 fsid[BTRFS_FSID_SIZE];
+       char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
+       struct seen_fsid *seen_fsid_hash[SEEN_FSID_HASH_SIZE] = { NULL, };
        enum { COMMIT_AFTER = 1, COMMIT_EACH = 2 };
 
        while (1) {
@@ -358,31 +361,74 @@ again:
                                path, strerror(errno));
                        ret = 1;
                }
+       } else if (commit_mode == COMMIT_AFTER) {
+               res = get_fsid(dname, fsid, 0);
+               if (res < 0) {
+                       error("unable to get fsid for '%s': %s",
+                               path, strerror(-res));
+                       error(
+                       "delete suceeded but commit may not be done in the end");
+                       ret = 1;
+                       goto out;
+               }
+
+               if (add_seen_fsid(fsid, seen_fsid_hash, fd, dirstream) == 0) {
+                       if (verbose > 0) {
+                               uuid_unparse(fsid, uuidbuf);
+                               printf("  new fs is found for '%s', fsid: %s\n",
+                                               path, uuidbuf);
+                       }
+                       /*
+                        * This is the first time a subvolume on this
+                        * filesystem is deleted, keep fd in order to issue
+                        * SYNC ioctl in the end
+                        */
+                       goto keep_fd;
+               }
        }
 
 out:
+       close_file_or_dir(fd, dirstream);
+keep_fd:
+       fd = -1;
+       dirstream = NULL;
        free(dupdname);
        free(dupvname);
        dupdname = NULL;
        dupvname = NULL;
        cnt++;
-       if (cnt < argc) {
-               close_file_or_dir(fd, dirstream);
-               /* avoid double free */
-               fd = -1;
-               dirstream = NULL;
+       if (cnt < argc)
                goto again;
-       }
 
-       if (commit_mode == COMMIT_AFTER && fd != -1) {
-               res = wait_for_commit(fd);
-               if (res < 0) {
-                       error("unable to do final sync after deletion: %s",
-                               strerror(errno));
-                       ret = 1;
+       if (commit_mode == COMMIT_AFTER) {
+               int slot;
+
+               /*
+                * Traverse seen_fsid_hash and issue SYNC ioctl on each
+                * filesystem
+                */
+               for (slot = 0; slot < SEEN_FSID_HASH_SIZE; slot++) {
+                       struct seen_fsid *seen = seen_fsid_hash[slot];
+
+                       while (seen) {
+                               res = wait_for_commit(seen->fd);
+                               if (res < 0) {
+                                       uuid_unparse(seen->fsid, uuidbuf);
+                                       error(
+                       "unable to do final sync after deletion: %s, fsid: %s",
+                                               strerror(errno), uuidbuf);
+                                       ret = 1;
+                               } else if (verbose > 0) {
+                                       uuid_unparse(seen->fsid, uuidbuf);
+                                       printf("final sync is done for fsid: %s\n",
+                                               uuidbuf);
+                               }
+                               seen = seen->next;
+                       }
                }
+               /* fd will also be closed in free_seen_fsid */
+               free_seen_fsid(seen_fsid_hash);
        }
-       close_file_or_dir(fd, dirstream);
 
        return ret;
 }
@@ -393,24 +439,32 @@ out:
  * - lowercase for enabling specific items in the output
  */
 static const char * const cmd_subvol_list_usage[] = {
-       "btrfs subvolume list [options] [-G [+|-]value] [-C [+|-]value] "
-       "[--sort=gen,ogen,rootid,path] <path>",
-       "List subvolumes (and snapshots)",
+       "btrfs subvolume list [options] <path>",
+       "List subvolumes and snapshots in the filesystem.",
        "",
-       "-p           print parent ID",
+       "Path filtering:",
+       "-o           print only subvolumes below specified path",
        "-a           print all the subvolumes in the filesystem and",
        "             distinguish absolute and relative path with respect",
        "             to the given <path>",
+       "",
+       "Field selection:",
+       "-p           print parent ID",
        "-c           print the ogeneration of the subvolume",
        "-g           print the generation of the subvolume",
-       "-o           print only subvolumes below specified path",
        "-u           print the uuid of subvolumes (and snapshots)",
        "-q           print the parent uuid of the snapshots",
        "-R           print the uuid of the received snapshots",
-       "-t           print the result as a table",
-       "-s           list snapshots only in the filesystem",
+       "",
+       "Type filtering:",
+       "-s           list only snapshots",
        "-r           list readonly subvolumes (including snapshots)",
        "-d           list deleted subvolumes that are not yet cleaned",
+       "",
+       "Other:",
+       "-t           print the result as a table",
+       "",
+       "Sorting:",
        "-G [+|-]value",
        "             filter the subvolumes by generation",
        "             (+value: >= value; -value: <= value; value: = value)",
@@ -804,8 +858,11 @@ out:
 }
 
 static const char * const cmd_subvol_set_default_usage[] = {
+       "btrfs subvolume set-default <subvolume>\n"
        "btrfs subvolume set-default <subvolid> <path>",
-       "Set the default subvolume of a filesystem",
+       "Set the default subvolume of the filesystem mounted as default.",
+       "The subvolume can be specified by its path,",
+       "or the pair of subvolume id and path to the filesystem.",
        NULL
 };
 
@@ -819,17 +876,43 @@ static int cmd_subvol_set_default(int argc, char **argv)
 
        clean_args_no_options(argc, argv, cmd_subvol_set_default_usage);
 
-       if (check_argc_exact(argc - optind, 2))
+       if (check_argc_min(argc - optind, 1) ||
+                       check_argc_max(argc - optind, 2))
                usage(cmd_subvol_set_default_usage);
 
-       subvolid = argv[optind];
-       path = argv[optind + 1];
+       if (argc - optind == 1) {
+               /* path to the subvolume is specified */
+               path = argv[optind];
 
-       objectid = arg_strtou64(subvolid);
+               ret = test_issubvolume(path);
+               if (ret < 0) {
+                       error("stat error: %s", strerror(-ret));
+                       return 1;
+               } else if (!ret) {
+                       error("'%s' is not a subvolume", path);
+                       return 1;
+               }
 
-       fd = btrfs_open_dir(path, &dirstream, 1);
-       if (fd < 0)
-               return 1;
+               fd = btrfs_open_dir(path, &dirstream, 1);
+               if (fd < 0)
+                       return 1;
+
+               ret = lookup_path_rootid(fd, &objectid);
+               if (ret) {
+                       error("unable to get subvol id: %s", strerror(-ret));
+                       close_file_or_dir(fd, dirstream);
+                       return 1;
+               }
+       } else {
+               /* subvol id and path to the filesystem are specified */
+               subvolid = argv[optind];
+               path = argv[optind + 1];
+               objectid = arg_strtou64(subvolid);
+
+               fd = btrfs_open_dir(path, &dirstream, 1);
+               if (fd < 0)
+                       return 1;
+       }
 
        ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
        e = errno;