summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmount/docs/libmount-sections.txt2
-rw-r--r--libmount/src/context.c20
-rw-r--r--libmount/src/fs.c52
-rw-r--r--libmount/src/libmount.h.in2
-rw-r--r--libmount/src/libmount.sym2
-rw-r--r--libmount/src/mountP.h11
-rw-r--r--libmount/src/tab.c34
-rw-r--r--libmount/src/tab_diff.c13
-rw-r--r--libmount/src/tab_parse.c3
-rw-r--r--libmount/src/tab_update.c17
10 files changed, 115 insertions, 41 deletions
diff --git a/libmount/docs/libmount-sections.txt b/libmount/docs/libmount-sections.txt
index 551ebedc1..97e0851e5 100644
--- a/libmount/docs/libmount-sections.txt
+++ b/libmount/docs/libmount-sections.txt
@@ -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
diff --git a/libmount/src/context.c b/libmount/src/context.c
index 12f22fc92..ea13f0d1e 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -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;
}
diff --git a/libmount/src/fs.c b/libmount/src/fs.c
index 97c606211..690428cda 100644
--- a/libmount/src/fs.c
+++ b/libmount/src/fs.c
@@ -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)
diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in
index b6c655467..29659628d 100644
--- a/libmount/src/libmount.h.in
+++ b/libmount/src/libmount.h.in
@@ -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,
diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym
index ae0bc59f8..621821e97 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -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;
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index 61b872eda..bf450a6c1 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -55,6 +55,13 @@
# 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 */
diff --git a/libmount/src/tab.c b/libmount/src/tab.c
index 098bf368c..58edf2f42 100644
--- a/libmount/src/tab.c
+++ b/libmount/src/tab.c
@@ -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);
diff --git a/libmount/src/tab_diff.c b/libmount/src/tab_diff.c
index 0ebdc1110..71ef0f419 100644
--- a/libmount/src/tab_diff.c
+++ b/libmount/src/tab_diff.c
@@ -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
diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c
index 24e84457e..e31dac8c2 100644
--- a/libmount/src/tab_parse.c
+++ b/libmount/src/tab_parse.c
@@ -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))
diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c
index 9603f77ec..b5c92726f 100644
--- a/libmount/src/tab_update.c
+++ b/libmount/src/tab_update.c
@@ -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);