]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: add reference counting to libmount_fs
authorKarel Zak <kzak@redhat.com>
Wed, 21 Aug 2013 10:31:43 +0000 (12:31 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 21 Aug 2013 10:48:42 +0000 (12:48 +0200)
 * mnt_new_fs() returns object with refcount=1
 * mnt_free_fs() does not care about reference counter

 * new functions mnt_ref_fs() and mnt_unref_fs()

 * mnt_table_add_fs() and mnt_table_rem_fs() uses reference counter

 * libmmnt_context uses reference counter for internal FS (as it could be
   shared outside the context)

 * backwardly incompatible change:

- FS could be deallocated after mnt_table_remove_fs()

 * it's recommended to use mnt_unref_fs() after mnt_table_add_fs()

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/docs/libmount-sections.txt
libmount/src/context.c
libmount/src/fs.c
libmount/src/libmount.h.in
libmount/src/libmount.sym
libmount/src/mountP.h
libmount/src/tab.c
libmount/src/tab_diff.c
libmount/src/tab_parse.c
libmount/src/tab_update.c

index 551ebedc1076e083518eaf2e237c98e2b3ca6d1b..97e0851e500c1810f9e8dbe4d7399ab69e25693b 100644 (file)
@@ -170,6 +170,8 @@ libmnt_fs
 mnt_copy_fs
 mnt_free_fs
 mnt_free_mntent
+mnt_ref_fs
+mnt_unref_fs
 mnt_fs_append_attributes
 mnt_fs_append_comment
 mnt_fs_append_options
index 12f22fc9245a953d4c5e781b53e9b566c20b8693..ea13f0d1e4a13f7e0ef5f5b889f27cc04d1f45b9 100644 (file)
@@ -109,7 +109,7 @@ void mnt_free_context(struct libmnt_context *cxt)
  * @cxt: mount context
  *
  * Resets all information in the context that is directly related to
- * the latest mount (spec, source, target, mount options, ....)
+ * the latest mount (spec, source, target, mount options, ...).
  *
  * The match patterns, cached fstab, cached canonicalized paths and tags and
  * [e]uid are not reset. You have to use
@@ -136,9 +136,7 @@ int mnt_reset_context(struct libmnt_context *cxt)
 
        fl = cxt->flags;
 
-       if (!(cxt->flags & MNT_FL_EXTERN_FS))
-               mnt_free_fs(cxt->fs);
-
+       mnt_unref_fs(cxt->fs);
        mnt_free_table(cxt->mtab);
 
        free(cxt->helper);
@@ -633,8 +631,9 @@ int mnt_context_is_loopdel(struct libmnt_context *cxt)
  * @fs: filesystem description
  *
  * The mount context uses private @fs by default. This function allows to
- * overwrite the private @fs with an external instance. Note that the external
- * @fs instance is not deallocated by mnt_free_context() or mnt_reset_context().
+ * overwrite the private @fs with an external instance. This function
+ * increments @fs reference counter (and deincrement reference counter of the
+ * old fs).
  *
  * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
  * functions, If the @fs is NULL, then all current FS specific settings (source,
@@ -646,10 +645,9 @@ int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
 {
        if (!cxt)
                return -EINVAL;
-       if (!(cxt->flags & MNT_FL_EXTERN_FS))
-               mnt_free_fs(cxt->fs);
 
-       set_flag(cxt, MNT_FL_EXTERN_FS, fs != NULL);
+       mnt_ref_fs(fs);                 /* new */
+       mnt_unref_fs(cxt->fs);          /* old */
        cxt->fs = fs;
        return 0;
 }
@@ -669,10 +667,8 @@ struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
        assert(cxt);
        if (!cxt)
                return NULL;
-       if (!cxt->fs) {
+       if (!cxt->fs)
                cxt->fs = mnt_new_fs();
-               cxt->flags &= ~MNT_FL_EXTERN_FS;
-       }
        return cxt->fs;
 }
 
index 97c6062111c753483bfd68ca9bdbce5446cedccd..690428cdab9550fb31b60ac7a76159b85461ebb1 100644 (file)
@@ -21,6 +21,9 @@
 /**
  * mnt_new_fs:
  *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the filesystem.
+ *
  * Returns: newly allocated struct libmnt_fs.
  */
 struct libmnt_fs *mnt_new_fs(void)
@@ -29,7 +32,7 @@ struct libmnt_fs *mnt_new_fs(void)
        if (!fs)
                return NULL;
 
-       /*DBG(FS, mnt_debug_h(fs, "alloc"));*/
+       fs->refcount = 1;
        INIT_LIST_HEAD(&fs->ents);
        return fs;
 }
@@ -38,7 +41,10 @@ struct libmnt_fs *mnt_new_fs(void)
  * mnt_free_fs:
  * @fs: fs pointer
  *
- * Deallocates the fs.
+ * Deallocates the fs. This function does not care about reference count. Don't
+ * use this function directly -- it's better to use use mnt_unref_fs().
+ *
+ * The reference counting is supported since util-linux v2.24.
  */
 void mnt_free_fs(struct libmnt_fs *fs)
 {
@@ -47,6 +53,7 @@ void mnt_free_fs(struct libmnt_fs *fs)
        list_del(&fs->ents);
 
        /*DBG(FS, mnt_debug_h(fs, "free"));*/
+       WARN_REFCOUNT(FS, fs, fs->refcount);
 
        free(fs->source);
        free(fs->bindsrc);
@@ -75,8 +82,45 @@ void mnt_free_fs(struct libmnt_fs *fs)
  */
 void mnt_reset_fs(struct libmnt_fs *fs)
 {
-       if (fs)
-               memset(fs, 0, sizeof(*fs));
+       int ref;
+
+       if (!fs)
+               return;
+
+       ref = fs->refcount;
+       memset(fs, 0, sizeof(*fs));
+       fs->refcount = ref;
+}
+
+/**
+ * mnt_ref_fs:
+ * @fs: fs pointer
+ *
+ * Increments reference counter.
+ */
+void mnt_ref_fs(struct libmnt_fs *fs)
+{
+       if (fs) {
+               fs->refcount++;
+               /*DBG(FS, mnt_debug_h(fs, "ref=%d", fs->refcount));*/
+       }
+}
+
+/**
+ * mnt_unref_fs:
+ * @fs: fs pointer
+ *
+ * De-increments reference counter, on zero the FS is automatically
+ * deallocated by mnt_free_fs().
+ */
+void mnt_unref_fs(struct libmnt_fs *fs)
+{
+       if (fs) {
+               fs->refcount--;
+               /*DBG(FS, mnt_debug_h(fs, "unref=%d", fs->refcount));*/
+               if (fs->refcount <= 0)
+                       mnt_free_fs(fs);
+       }
 }
 
 static inline int update_str(char **dest, const char *src)
index b6c65546744534ed6b30029538f3f222674d1c6e..29659628dd9eba062fc5052504ac2a6148d2f859 100644 (file)
@@ -302,6 +302,8 @@ extern int mnt_lock_block_signals(struct libmnt_lock *ml, int enable);
 extern struct libmnt_fs *mnt_new_fs(void)
                        __ul_attribute__((warn_unused_result));
 extern void mnt_free_fs(struct libmnt_fs *fs);
+extern void mnt_ref_fs(struct libmnt_fs *fs);
+extern void mnt_unref_fs(struct libmnt_fs *fs);
 
 extern void mnt_reset_fs(struct libmnt_fs *fs);
 extern struct libmnt_fs *mnt_copy_fs(struct libmnt_fs *dest,
index ae0bc59f88dbdc2e7215f10a02671c4a500e8fc4..621821e9779469b4787bca67987e1292bf1a4941 100644 (file)
@@ -265,6 +265,7 @@ global:
        mnt_fs_append_comment;
        mnt_fs_get_comment;
        mnt_fs_set_comment;
+       mnt_ref_fs;
        mnt_table_append_intro_comment;
        mnt_table_append_trailing_comment;
        mnt_table_enable_comments;
@@ -280,4 +281,5 @@ global:
        mnt_table_set_userdata;
        mnt_table_with_comments;
        mnt_table_write_file;
+       mnt_unref_fs;
 } MOUNT_2.23;
index 61b872eda09347083f33df8fd4d8bf1cf3591214..bf450a6c1bfd25eaef48db5b2921711ddef3b738 100644 (file)
 # include <stdio.h>
 # include <stdarg.h>
 
+# define WARN_REFCOUNT(m, o, r) \
+                       do { \
+                               if ((MNT_DEBUG_ ## m) & libmount_debug_mask && r != 0) \
+                                       fprintf(stderr, "%d: libmount: %8s: [%p]: *** deallocates with refcount=%d\n", \
+                                                       getpid(), # m, o, r); \
+                       } while (0)
+
 # define ON_DBG(m, x)  do { \
                                if ((MNT_DEBUG_ ## m) & libmount_debug_mask) { \
                                        x; \
@@ -100,6 +107,7 @@ mnt_debug_h(void *handler, const char *mesg, ...)
 }
 
 #else /* !CONFIG_LIBMOUNT_DEBUG */
+# define WARN_REFCOUNT(m,o,r)  do { ; } while (0)
 # define ON_DBG(m,x) do { ; } while (0)
 # define DBG(m,x) do { ; } while (0)
 # define DBG_FLUSH do { ; } while(0)
@@ -209,6 +217,7 @@ struct libmnt_iter {
 struct libmnt_fs {
        struct list_head ents;
 
+       int             refcount;       /* reference counter */
        int             id;             /* mountinfo[1]: ID */
        int             parent;         /* mountinfo[2]: parent */
        dev_t           devno;          /* mountinfo[3]: st_dev */
@@ -266,6 +275,7 @@ struct libmnt_fs {
  */
 struct libmnt_table {
        int             fmt;            /* MNT_FMT_* file format */
+       int             nents;          /* number of entries */
        int             comms;          /* enable/disable comment parsing */
        char            *comm_intro;    /* First comment in file */
        char            *comm_tail;     /* Last comment in file */
@@ -381,7 +391,6 @@ struct libmnt_context
 #define MNT_FL_FORK            (1 << 12)
 #define MNT_FL_NOSWAPMATCH     (1 << 13)
 
-#define MNT_FL_EXTERN_FS       (1 << 15)       /* cxt->fs is not private */
 #define MNT_FL_EXTERN_FSTAB    (1 << 16)       /* cxt->fstab is not private */
 #define MNT_FL_EXTERN_CACHE    (1 << 17)       /* cxt->cache is not private */
 
index 098bf368c5f96300aa381f319906bb716950b9bf..58edf2f4261449e1dc649ba48e7837b36f1e0a85 100644 (file)
@@ -75,7 +75,8 @@ struct libmnt_table *mnt_new_table(void)
  * mnt_reset_table:
  * @tb: tab pointer
  *
- * Deallocates all entries (filesystems) from the table.
+ * Removes all entries (filesystems) from the table. The filesystems with zero
+ * reference count will be deallocated.
  *
  * Returns: 0 on success or negative number in case of error.
  */
@@ -89,9 +90,10 @@ int mnt_reset_table(struct libmnt_table *tb)
        while (!list_empty(&tb->ents)) {
                struct libmnt_fs *fs = list_entry(tb->ents.next,
                                                  struct libmnt_fs, ents);
-               mnt_free_fs(fs);
+               mnt_table_remove_fs(tb, fs);
        }
 
+       tb->nents = 0;
        return 0;
 }
 
@@ -118,21 +120,11 @@ void mnt_free_table(struct libmnt_table *tb)
  * mnt_table_get_nents:
  * @tb: pointer to tab
  *
- * Returns: number of valid entries in tab.
+ * Returns: number of entries in table.
  */
 int mnt_table_get_nents(struct libmnt_table *tb)
 {
-       struct list_head *p;
-       int i = 0;
-
-       assert(tb);
-       if (!tb)
-               return -EINVAL;
-       if (list_empty(&tb->ents))
-               return 0;
-       list_for_each(p, &tb->ents)
-               i++;
-       return i;
+       return tb ? tb->nents : 0;
 }
 
 /**
@@ -376,7 +368,9 @@ struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb)
  * @tb: tab pointer
  * @fs: new entry
  *
- * Adds a new entry to tab.
+ * Adds a new entry to tab and increment @fs reference counter. Don't forget to
+ * use mnt_unref_fs() after mnt_table_add_fs() you want to keep the @fs
+ * referenced by the table only.
  *
  * Returns: 0 on success or negative number in case of error.
  */
@@ -388,7 +382,9 @@ int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
        if (!tb || !fs)
                return -EINVAL;
 
+       mnt_ref_fs(fs);
        list_add_tail(&fs->ents, &tb->ents);
+       tb->nents++;
 
        DBG(TAB, mnt_debug_h(tb, "add entry: %s %s",
                        mnt_fs_get_source(fs), mnt_fs_get_target(fs)));
@@ -400,6 +396,10 @@ int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
  * @tb: tab pointer
  * @fs: new entry
  *
+ * Removes the @fs from the table and de-increment reference counter of the @fs. The
+ * filesystem with zero reference counter will be deallocated. Don't forget to use
+ * mnt_ref_fs() before call mnt_table_remove_fs() if you want to use @fs later.
+ *
  * Returns: 0 on success or negative number in case of error.
  */
 int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
@@ -410,6 +410,8 @@ int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
        if (!tb || !fs)
                return -EINVAL;
        list_del(&fs->ents);
+       mnt_unref_fs(fs);
+       tb->nents--;
        return 0;
 }
 
@@ -1387,7 +1389,7 @@ int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
 
        printf("COPY:\n");
        mnt_fs_print_debug(fs, stdout);
-       mnt_free_fs(fs);
+       mnt_unref_fs(fs);
        rc = 0;
 done:
        mnt_free_table(tb);
index 0ebdc11107c86369e86401cbff58d4b5d3276422..71ef0f41919bf9208e644ffe3e428f06ad91b9c2 100644 (file)
@@ -54,6 +54,8 @@ static void free_tabdiff_entry(struct tabdiff_entry *de)
        if (!de)
                return;
        list_del(&de->changes);
+       mnt_unref_fs(de->new_fs);
+       mnt_unref_fs(de->old_fs);
        free(de);
 }
 
@@ -135,6 +137,9 @@ static int tabdiff_reset(struct libmnt_tabdiff *df)
                list_del(&de->changes);
                list_add_tail(&de->changes, &df->unused);
 
+               mnt_unref_fs(de->new_fs);
+               mnt_unref_fs(de->old_fs);
+
                de->new_fs = de->old_fs = NULL;
                de->oper = 0;
        }
@@ -164,6 +169,12 @@ static int tabdiff_add_entry(struct libmnt_tabdiff *df, struct libmnt_fs *old,
 
        INIT_LIST_HEAD(&de->changes);
 
+       mnt_ref_fs(new);
+       mnt_ref_fs(old);
+
+       mnt_unref_fs(de->new_fs);
+       mnt_unref_fs(de->old_fs);
+
        de->old_fs = old;
        de->new_fs = new;
        de->oper = oper;
@@ -280,6 +291,8 @@ int mnt_diff_tables(struct libmnt_tabdiff *df, struct libmnt_table *old_tab,
 
                        de = tabdiff_get_mount(df, src, mnt_fs_get_id(fs));
                        if (de) {
+                               mnt_ref_fs(fs);
+                               mnt_unref_fs(de->old_fs);
                                de->oper = MNT_TABDIFF_MOVE;
                                de->old_fs = fs;
                        } else
index 24e84457e58b9b9e0927d4141be508b581e3a8c6..e31dac8c2d4b437c99219fe9b6a410b65998b8c2 100644 (file)
@@ -630,8 +630,9 @@ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filenam
                        if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO)
                                rc = kernel_fs_postparse(tb, fs, &tid, filename);
                }
+               mnt_unref_fs(fs);
+
                if (rc) {
-                       mnt_free_fs(fs);
                        if (rc == 1)
                                continue;       /* recoverable error */
                        if (feof(f))
index 9603f77ecde4d23517f1e39ee596404b5af0a283..b5c92726f4d44d7b8c0a9511cfc082f354f92886 100644 (file)
@@ -70,7 +70,7 @@ void mnt_free_update(struct libmnt_update *upd)
 
        DBG(UPDATE, mnt_debug_h(upd, "free"));
 
-       mnt_free_fs(upd->fs);
+       mnt_unref_fs(upd->fs);
        mnt_free_table(upd->mountinfo);
        free(upd->target);
        free(upd->filename);
@@ -180,7 +180,7 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
                DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
        }
 
-       mnt_free_fs(upd->fs);
+       mnt_unref_fs(upd->fs);
        free(upd->target);
        upd->ready = FALSE;
        upd->fs = NULL;
@@ -350,7 +350,7 @@ static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs,
        return 0;
 err:
        free(u);
-       mnt_free_fs(upd->fs);
+       mnt_unref_fs(upd->fs);
        upd->fs = NULL;
        return rc;
 }
@@ -671,6 +671,8 @@ static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd)
                return -ENOMEM;
 
        mnt_table_add_fs(tb, fs);
+       mnt_unref_fs(fs);
+
        return update_table(upd, tb);
 }
 
@@ -722,7 +724,6 @@ static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc
                if (rem) {
                        mnt_table_remove_fs(tb, rem);
                        rc = update_table(upd, tb);
-                       mnt_free_fs(rem);
                }
        }
        if (lc)
@@ -905,7 +906,7 @@ static int test_add(struct libmnt_test *ts, int argc, char *argv[])
        mnt_fs_set_options(fs, argv[4]);
 
        rc = update(NULL, fs, 0);
-       mnt_free_fs(fs);
+       mnt_unref_fs(fs);
        return rc;
 }
 
@@ -928,7 +929,7 @@ static int test_move(struct libmnt_test *ts, int argc, char *argv[])
 
        rc = update(NULL, fs, MS_MOVE);
 
-       mnt_free_fs(fs);
+       mnt_unref_fs(fs);
        return rc;
 }
 
@@ -943,7 +944,7 @@ static int test_remount(struct libmnt_test *ts, int argc, char *argv[])
        mnt_fs_set_options(fs, argv[2]);
 
        rc = update(NULL, fs, MS_REMOUNT);
-       mnt_free_fs(fs);
+       mnt_unref_fs(fs);
        return rc;
 }
 
@@ -962,7 +963,9 @@ static int test_replace(struct libmnt_test *ts, int argc, char *argv[])
        mnt_fs_set_source(fs, argv[1]);
        mnt_fs_set_target(fs, argv[2]);
        mnt_fs_append_comment(fs, "# this is new filesystem\n");
+
        mnt_table_add_fs(tb, fs);
+       mnt_unref_fs(fs);
 
        rc = mnt_table_replace_file(tb, mnt_get_fstab_path());
        mnt_free_table(tb);