memory allocated by device_list_add has to be freed, the
function introduced here device_list_remove() would just
go that.
however the challenging part is about where we would
call this function.

there are two ways its handled
 the threads calling open_ctree_broken(), open_ctree() and
 open_ctree_fd() (which leads call to device_list_add)
 would anyway call close_ctree() so we put device_list_remove()
 there which will take care of freeing memory.

 now for threads calling device_list_add() outside of
 open_ctree(), has to call device_list_remove() separately
 which can be called as a last function in the thread
 this patch just does that.

device_list_remove accepts() NULL (deletes entire list)
or fsid (which would delete only the fsid matched in the
device_fs list). As of now though all calling functions
use NULL, I see potential that we would use fsid when we
have to create a single device list using both the
device-tree and from the btrfs-kernel.

further, mkfs.c thread should call device_list_remove()
as well, however mkfs.c uses a lot of in-flight exits()
which makes it very difficult to bring in this fix into
mkfs.c.  I shall be doing it in a separate patch.

Signed-off-by: Anand Jain <anand.j...@oracle.com>
---
 cmds-device.c     |    4 +++
 cmds-filesystem.c |   11 ++++++++-
 cmds-replace.c    |    2 +
 cmds-scrub.c      |    3 ++
 disk-io.c         |    1 +
 mkfs.c            |    1 +
 utils.h           |    1 +
 volumes.c         |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 volumes.h         |    3 ++
 9 files changed, 79 insertions(+), 3 deletions(-)

diff --git a/cmds-device.c b/cmds-device.c
index 9525fcf..e4a1f1b 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -29,6 +29,7 @@
 #include "utils.h"
 
 #include "commands.h"
+#include "volumes.h"
 
 /* FIXME - imported cruft, fix sparse errors and warnings */
 #ifdef __CHECKER__
@@ -128,6 +129,7 @@ static int cmd_add_dev(int argc, char **argv)
        }
 
        close(fdmnt);
+       device_list_remove(NULL);
        if (ret)
                return ret+20;
        else
@@ -213,6 +215,7 @@ static int cmd_scan_dev(int argc, char **argv)
                int ret;
                printf("Scanning for Btrfs filesystems\n");
                ret = scan_for_btrfs(where, 1);
+               device_list_remove(NULL);
                if (ret){
                        fprintf(stderr, "ERROR: error %d while scanning\n", 
ret);
                        return 18;
@@ -397,6 +400,7 @@ static int cmd_dev_stats(int argc, char **argv)
 out:
        free(di_args);
        close(fdmnt);
+       device_list_remove(NULL);
 
        return err;
 }
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index a028e1d..1c26476 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -455,6 +455,7 @@ static int cmd_show(int argc, char **argv)
                print_one_uuid(fs_devices);
        }
        printf("%s\n", BTRFS_BUILD_VERSION);
+       device_list_remove(NULL);
        return 0;
 }
 
@@ -683,13 +684,19 @@ static const char * const cmd_label_usage[] = {
 
 static int cmd_label(int argc, char **argv)
 {
+       int ret;
        if (check_argc_min(argc, 2) || check_argc_max(argc, 3))
                usage(cmd_label_usage);
 
        if (argc > 2)
-               return set_label(argv[1], argv[2]);
+               ret = set_label(argv[1], argv[2]);
        else
-               return get_label(argv[1]);
+               ret = get_label(argv[1]);
+
+       if (is_existing_blk_or_reg_file(argv[1]))
+               device_list_remove(NULL);
+
+       return ret;
 }
 
 const struct cmd_group filesystem_cmd_group = {
diff --git a/cmds-replace.c b/cmds-replace.c
index c68986a..99a5abc 100644
--- a/cmds-replace.c
+++ b/cmds-replace.c
@@ -340,6 +340,7 @@ static int cmd_start_replace(int argc, char **argv)
                }
        }
        close(fdmnt);
+       device_list_remove(NULL);
        return 0;
 
 leave_with_error:
@@ -349,6 +350,7 @@ leave_with_error:
                close(fdsrcdev);
        if (fddstdev != -1)
                close(fddstdev);
+       device_list_remove(NULL);
        return -1;
 }
 
diff --git a/cmds-scrub.c b/cmds-scrub.c
index 95dfee3..08aab54 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -1496,6 +1496,7 @@ out:
                        unlink(sock_path);
        }
        close(fdmnt);
+       device_list_remove(NULL);
 
        if (err)
                return 1;
@@ -1564,6 +1565,7 @@ static int cmd_scrub_cancel(int argc, char **argv)
 out:
        if (fdmnt != -1)
                close(fdmnt);
+       device_list_remove(NULL);
        return ret;
 }
 
@@ -1722,6 +1724,7 @@ out:
        free(di_args);
        if (fdres > -1)
                close(fdres);
+       device_list_remove(NULL);
 
        return err;
 }
diff --git a/disk-io.c b/disk-io.c
index 3937e3f..9b72576 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -1338,6 +1338,7 @@ int close_ctree(struct btrfs_root *root)
        }
 
        close_all_devices(fs_info);
+       device_list_remove(NULL);
        free_mapping_cache(fs_info);
        extent_io_tree_cleanup(&fs_info->extent_cache);
        extent_io_tree_cleanup(&fs_info->free_space_cache);
diff --git a/mkfs.c b/mkfs.c
index 95fceb3..5d131dd 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -1461,6 +1461,7 @@ int main(int ac, char **av)
                if (is_block_device(file))
                        if (test_dev_for_mkfs(file, force_overwrite, estr)) {
                                fprintf(stderr, "Error: %s", estr);
+                               device_list_remove(NULL);
                                exit(1);
                        }
        }
diff --git a/utils.h b/utils.h
index 1fa1c5a..f5b03a7 100644
--- a/utils.h
+++ b/utils.h
@@ -70,4 +70,5 @@ u64 btrfs_device_size(int fd, struct stat *st);
 int test_dev_for_mkfs(char *file, int force_overwrite, char *estr);
 int scan_for_btrfs(int where, int update_kernel);
 int get_label_mounted(const char *mount_path, char *labelp);
+int is_existing_blk_or_reg_file(const char* filename);
 #endif
diff --git a/volumes.c b/volumes.c
index 00c384a..fa27055 100644
--- a/volumes.c
+++ b/volumes.c
@@ -87,7 +87,7 @@ static struct btrfs_fs_devices *find_fsid(u8 *fsid)
        return NULL;
 }
 
-static int device_list_add(const char *path,
+int device_list_add(const char *path,
                           struct btrfs_super_block *disk_super,
                           u64 devid, struct btrfs_fs_devices **fs_devices_ret)
 {
@@ -155,6 +155,60 @@ static int device_list_add(const char *path,
        return 0;
 }
 
+/* This will remove given fsid and it devices from the list,
+ * or when arg is NULL it will delete all.
+ */
+int device_list_remove(u8 *fsid)
+{
+       struct list_head *fsids;
+       struct list_head *cur_fsid;
+       struct btrfs_fs_devices *fs_devices;
+       struct list_head *cur_dev;
+       struct btrfs_device *device;
+       int del = 1;
+
+       fsids = btrfs_scanned_uuids();
+       list_for_each(cur_fsid, fsids) {
+               fs_devices = list_entry(cur_fsid, struct btrfs_fs_devices,
+                               list);
+               if (fsid && memcmp(fs_devices->fsid, fsid, BTRFS_FSID_SIZE))
+                       continue;
+
+               /* first check if all devs are closed before remove */
+               list_for_each(cur_dev, &fs_devices->devices) {
+                       device = list_entry(cur_dev,
+                                       struct btrfs_device, dev_list);
+                       if (device->fd > 0) {
+                               fprintf(stderr, "attempted to remove device "\
+                                       "list without closing\n");
+                               if (fsid)
+                                       return 1;
+                               else {
+                                       del = 0;
+                                       break;
+                               }
+                       }
+               }
+
+               if (del) {
+                       list_for_each(cur_dev, &fs_devices->devices) {
+                               device = list_entry(cur_dev,
+                                       struct btrfs_device, dev_list);
+                               list_del(&device->dev_list);
+                               if (device->name)
+                                       kfree(device->name);
+                               if (device->label)
+                                       kfree(device->label);
+                               kfree(device);
+                       }
+                       list_del(&fs_devices->list);
+                       kfree(fs_devices);
+               }
+               del = 1;
+       }
+       return 0;
+}
+
 int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 {
        struct btrfs_fs_devices *seed_devices;
diff --git a/volumes.h b/volumes.h
index 911f788..55a0b71 100644
--- a/volumes.h
+++ b/volumes.h
@@ -190,4 +190,7 @@ int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
 struct btrfs_device *btrfs_find_device_by_devid(struct btrfs_root *root,
                                                 u64 devid, int instance);
+int device_list_add(const char *path, struct btrfs_super_block *disk_super,
+                          u64 devid, struct btrfs_fs_devices **fs_devices_ret);
+int device_list_remove(u8 *fsid);
 #endif
-- 
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to