]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: optimize mtab and utab parsing in umount
authorKarel Zak <kzak@redhat.com>
Tue, 25 Sep 2012 14:47:18 +0000 (16:47 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 25 Sep 2012 14:47:18 +0000 (16:47 +0200)
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>
libmount/src/context.c
libmount/src/context_umount.c
libmount/src/mountP.h
libmount/src/tab_parse.c

index d6f905039a6c2b43fe566e4c07dd13c3e3a87bc6..d10afa36df74bee29e67b434a69f8d7d41436baa 100644 (file)
@@ -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
index 17ec1f0a48bdc609f9f5da4ec0844149bcc4cef9..566bb211513cfd88089b33729a9f5b69bcb898fa 100644 (file)
 # 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;
index 0ef073a69ac46d617bd0d6af98762f61c3fd7227..bbaa2c6c4d484adc072c31bcbbd90db3f8dd61fc 100644 (file)
@@ -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);
index ab5d51acd4dff0bdb28d7cb2002c45dab768531d..a9a8f0fb260c60898800f368f78b7242e9e1fc88 100644 (file)
@@ -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;