diff options
author | Karel Zak | 2012-09-25 16:47:18 +0200 |
---|---|---|
committer | Karel Zak | 2012-09-25 16:47:18 +0200 |
commit | 4709c9e6a19f46bbd085199607438b5ec9f0b0f6 (patch) | |
tree | 3176bafe0b5e6377efff421c46672d7b1415a54d /libmount/src | |
parent | libmount: user-mounted loopback fs cannot be unmounted by user (diff) | |
download | kernel-qcow2-util-linux-4709c9e6a19f46bbd085199607438b5ec9f0b0f6.tar.gz kernel-qcow2-util-linux-4709c9e6a19f46bbd085199607438b5ec9f0b0f6.tar.xz kernel-qcow2-util-linux-4709c9e6a19f46bbd085199607438b5ec9f0b0f6.zip |
libmount: optimize mtab and utab parsing in umount
create 8000 NFS mountpoints:
#!/bin/bash
mount=/tmp/mount
if [ ! -d $mount ]; then
mkdir -p $mount
fi
for dir in {1..8000}; do
if [ ! -d $mount/$dir ]; then
mkdir -p $mount/$dir
fi
echo mount $dir
mount -t nfs 127.0.0.1:/ $mount/$dir
done
old version:
time ./umount /tmp/mount/2255
real 0m1.254s
user 0m1.002s
sys 0m0.238s
new version:
time ./umount /tmp/mount/2244
real 0m0.332s
user 0m0.111s
sys 0m0.218s
Reported-by: chenditang <chendt.fnst@cn.fujitsu.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libmount/src')
-rw-r--r-- | libmount/src/context.c | 26 | ||||
-rw-r--r-- | libmount/src/context_umount.c | 41 | ||||
-rw-r--r-- | libmount/src/mountP.h | 15 | ||||
-rw-r--r-- | libmount/src/tab_parse.c | 31 |
4 files changed, 112 insertions, 1 deletions
diff --git a/libmount/src/context.c b/libmount/src/context.c index d6f905039..d10afa36d 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -923,6 +923,10 @@ int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb) if (cxt->table_errcb) mnt_table_set_parser_errcb(cxt->mtab, cxt->table_errcb); + if (cxt->table_fltrcb) + mnt_table_set_parser_fltrcb(cxt->mtab, + cxt->table_fltrcb, + cxt->table_fltrcb_data); rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path); if (rc) @@ -937,6 +941,28 @@ int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb) return 0; } +/* + * Allows to specify filter for tab file entries. The filter is called by + * table parser. Currently used for mtab and utab only. + */ +int mnt_context_set_tabfilter(struct libmnt_context *cxt, + int (*fltr)(struct libmnt_fs *, void *), + void *data) +{ + if (!cxt) + return -EINVAL; + + cxt->table_fltrcb = fltr; + cxt->table_fltrcb_data = data; + + if (cxt->mtab) + mnt_table_set_parser_fltrcb(cxt->mtab, + cxt->table_fltrcb, + cxt->table_fltrcb_data); + + return 0; +} + /** * mnt_context_get_table: * @cxt: mount context diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c index 17ec1f0a4..566bb2115 100644 --- a/libmount/src/context_umount.c +++ b/libmount/src/context_umount.c @@ -38,6 +38,20 @@ # define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */ #endif +/* + * Called by mtab parser to filter out entries, nonzero means that + * entry has to be filter out. + */ +static int mtab_filter(struct libmnt_fs *fs, void *data) +{ + if (!fs || !data) + return 0; + if (mnt_fs_streq_target(fs, data)) + return 0; + if (mnt_fs_streq_srcpath(fs, data)) + return 0; + return 1; +} static int lookup_umount_fs(struct libmnt_context *cxt) { @@ -45,6 +59,8 @@ static int lookup_umount_fs(struct libmnt_context *cxt) const char *tgt; struct libmnt_table *mtab = NULL; struct libmnt_fs *fs; + struct libmnt_cache *cache = NULL; + char *cn_tgt = NULL; assert(cxt); assert(cxt->fs); @@ -56,7 +72,32 @@ static int lookup_umount_fs(struct libmnt_context *cxt) DBG(CXT, mnt_debug_h(cxt, "umount: undefined target")); return -EINVAL; } + + /* + * The mtab file maybe huge and on systems with utab we have to merge + * userspace mount options into /proc/self/mountinfo. This all is + * expensive. The mtab filter allows to filter out entries, then + * mtab and utab are very tiny files. + * + * *but*... the filter uses mnt_fs_streq_{target,srcpath} functions + * where LABEL, UUID or symlinks are to canonicalized. It means that + * it's usable only for canonicalized stuff (e.g. kernel mountinfo). + */ + if (!cxt->mtab_writable && *tgt == '/') { + /* we'll canonicalized /proc/self/mountinfo */ + cache = mnt_context_get_cache(cxt); + cn_tgt = mnt_resolve_path(tgt, cache); + if (cn_tgt) + mnt_context_set_tabfilter(cxt, mtab_filter, cn_tgt); + } rc = mnt_context_get_mtab(cxt, &mtab); + + if (cn_tgt) { + mnt_context_set_tabfilter(cxt, NULL, NULL); + if (!cache) + free(cn_tgt); + } + if (rc) { DBG(CXT, mnt_debug_h(cxt, "umount: failed to read mtab")); return rc; diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index 0ef073a69..bbaa2c6c4 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -148,6 +148,10 @@ extern int mnt_get_filesystems(char ***filesystems, const char *pattern); extern void mnt_free_filesystems(char **filesystems); /* tab.c */ +extern int mnt_table_set_parser_fltrcb( struct libmnt_table *tb, + int (*cb)(struct libmnt_fs *, void *), + void *data); + extern struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb, struct libmnt_fs *fs, unsigned long mountflags, @@ -248,6 +252,10 @@ struct libmnt_table { int (*errcb)(struct libmnt_table *tb, const char *filename, int line); + int (*fltrcb)(struct libmnt_fs *fs, void *data); + void *fltrcb_data; + + struct list_head ents; /* list of entries (libmnt_fs) */ }; @@ -285,6 +293,9 @@ struct libmnt_context int (*table_errcb)(struct libmnt_table *tb, /* callback for libmnt_table structs */ const char *filename, int line); + int (*table_fltrcb)(struct libmnt_fs *fs, void *data); /* callback for libmnt_table structs */ + void *table_fltrcb_data; + char *(*pwd_get_cb)(struct libmnt_context *); /* get encryption password */ void (*pwd_release_cb)(struct libmnt_context *, char *); /* release password */ @@ -395,6 +406,10 @@ extern int mnt_context_clear_loopdev(struct libmnt_context *cxt); extern int mnt_fork_context(struct libmnt_context *cxt); +extern int mnt_context_set_tabfilter(struct libmnt_context *cxt, + int (*fltr)(struct libmnt_fs *, void *), + void *data); + /* tab_update.c */ extern int mnt_update_set_filename(struct libmnt_update *upd, const char *filename, int userspace_only); diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c index ab5d51acd..a9a8f0fb2 100644 --- a/libmount/src/tab_parse.c +++ b/libmount/src/tab_parse.c @@ -487,6 +487,10 @@ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filenam goto err; rc = mnt_table_parse_next(tb, f, fs, filename, &nlines); + + if (!rc && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data)) + rc = 1; /* filtered out by callback... */ + if (!rc) { rc = mnt_table_add_fs(tb, fs); fs->flags |= flags; @@ -756,6 +760,22 @@ int mnt_table_set_parser_errcb(struct libmnt_table *tb, return 0; } +/* + * Filter out entries during tab file parsing. If @cb returns 1 then the entry + * is ignored. + */ +int mnt_table_set_parser_fltrcb(struct libmnt_table *tb, + int (*cb)(struct libmnt_fs *, void *), + void *data) +{ + assert(tb); + + DBG(TAB, mnt_debug_h(tb, "set table parser filter")); + tb->fltrcb = cb; + tb->fltrcb_data = data; + return 0; +} + /** * mnt_table_parse_swaps: * @tb: table @@ -925,7 +945,16 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename) */ utab = mnt_get_utab_path(); if (utab) { - struct libmnt_table *u_tb = __mnt_new_table_from_file(utab, MNT_FMT_UTAB); + struct libmnt_table *u_tb = mnt_new_table(); + if (u_tb) { + u_tb->fmt = MNT_FMT_UTAB; + mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data); + + if (mnt_table_parse_file(u_tb, utab) != 0) { + mnt_free_table(u_tb); + u_tb = NULL; + } + } if (u_tb) { struct libmnt_fs *u_fs; |