summaryrefslogtreecommitdiffstats
path: root/libmount
diff options
context:
space:
mode:
authorKarel Zak2012-09-25 16:47:18 +0200
committerKarel Zak2012-09-25 16:47:18 +0200
commit4709c9e6a19f46bbd085199607438b5ec9f0b0f6 (patch)
tree3176bafe0b5e6377efff421c46672d7b1415a54d /libmount
parentlibmount: user-mounted loopback fs cannot be unmounted by user (diff)
downloadkernel-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')
-rw-r--r--libmount/src/context.c26
-rw-r--r--libmount/src/context_umount.c41
-rw-r--r--libmount/src/mountP.h15
-rw-r--r--libmount/src/tab_parse.c31
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;