diff options
Diffstat (limited to 'libmount/src')
-rw-r--r-- | libmount/src/context.c | 20 | ||||
-rw-r--r-- | libmount/src/fs.c | 52 | ||||
-rw-r--r-- | libmount/src/libmount.h.in | 2 | ||||
-rw-r--r-- | libmount/src/libmount.sym | 2 | ||||
-rw-r--r-- | libmount/src/mountP.h | 11 | ||||
-rw-r--r-- | libmount/src/tab.c | 34 | ||||
-rw-r--r-- | libmount/src/tab_diff.c | 13 | ||||
-rw-r--r-- | libmount/src/tab_parse.c | 3 | ||||
-rw-r--r-- | libmount/src/tab_update.c | 17 |
9 files changed, 113 insertions, 41 deletions
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); |