summaryrefslogtreecommitdiffstats
path: root/libmount/src/tab_parse.c
diff options
context:
space:
mode:
authorKarel Zak2014-03-03 10:36:15 +0100
committerKarel Zak2014-03-03 10:36:15 +0100
commit6a52473ecd877227f6f7da2b95da0b51593ffec1 (patch)
tree6dd6778cf47560258450468de30c6e49c4adc169 /libmount/src/tab_parse.c
parentdocs: refresh TODO (diff)
downloadkernel-qcow2-util-linux-6a52473ecd877227f6f7da2b95da0b51593ffec1.tar.gz
kernel-qcow2-util-linux-6a52473ecd877227f6f7da2b95da0b51593ffec1.tar.xz
kernel-qcow2-util-linux-6a52473ecd877227f6f7da2b95da0b51593ffec1.zip
umount: don't use mountinfo if possible
The umount(8) always parses /proc/self/mountinfo to get fstype and to merge kernel mount options with userspace mount options from /run/mount/utab. This behavior is overkill in many cases and it's pretty expensive as kernel has to always compose *whole* mountinfo. This performance disadvantage is visible for crazy use-cases with huge number of mountpoints and frequently called umount(8). It seems that we can bypass /proc/self/mountinfo by statfs() to get filesystem type (statfs.f_type magic) and analyze /run/mount/utab before we parse mountinfo. This optimization is not used when: * umount(8) executed by non-root (as user= in utab is expected) * umount --lazy / --force (target is probably unreachable NFS, then use statfs() is pretty bad idea) * target is not a directory (e.g. umount /dev/sda1) * there is (deprecated) writeable mtab Reported-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libmount/src/tab_parse.c')
-rw-r--r--libmount/src/tab_parse.c62
1 files changed, 36 insertions, 26 deletions
diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c
index 81232736c..7c73cc553 100644
--- a/libmount/src/tab_parse.c
+++ b/libmount/src/tab_parse.c
@@ -1036,23 +1036,10 @@ static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct
return fs;
}
-/**
- * mnt_table_parse_mtab:
- * @tb: table
- * @filename: overwrites default (/etc/mtab or $LIBMOUNT_MTAB) or NULL
- *
- * This function parses /etc/mtab or /proc/self/mountinfo +
- * /run/mount/utabs or /proc/mounts.
- *
- * See also mnt_table_set_parser_errcb().
- *
- * Returns: 0 on success or negative number in case of error.
- */
-int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
+int __mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename,
+ struct libmnt_table *u_tb)
{
- int rc;
- const char *utab = NULL;
- struct libmnt_table *u_tb;
+ int rc = 0, priv_utab = 0;
assert(tb);
@@ -1083,18 +1070,23 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
/*
* try to read the user specific information from /run/mount/utabs
*/
- utab = mnt_get_utab_path();
- if (!utab || is_file_empty(utab))
- return 0;
+ if (!u_tb) {
+ const char *utab = mnt_get_utab_path();
+ if (!utab || is_file_empty(utab))
+ return 0;
+
+ u_tb = mnt_new_table();
+ if (!u_tb)
+ return -ENOMEM;
- u_tb = mnt_new_table();
- if (!u_tb)
- return -ENOMEM;
+ u_tb->fmt = MNT_FMT_UTAB;
+ mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data);
- u_tb->fmt = MNT_FMT_UTAB;
- mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data);
+ rc = mnt_table_parse_file(u_tb, utab);
+ priv_utab = 1;
+ }
- if (mnt_table_parse_file(u_tb, utab) == 0) {
+ if (rc == 0) {
struct libmnt_fs *u_fs;
struct libmnt_iter itr;
@@ -1105,6 +1097,24 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
mnt_table_merge_user_fs(tb, u_fs);
}
- mnt_unref_table(u_tb);
+
+ if (priv_utab)
+ mnt_unref_table(u_tb);
return 0;
}
+/**
+ * mnt_table_parse_mtab:
+ * @tb: table
+ * @filename: overwrites default (/etc/mtab or $LIBMOUNT_MTAB) or NULL
+ *
+ * This function parses /etc/mtab or /proc/self/mountinfo +
+ * /run/mount/utabs or /proc/mounts.
+ *
+ * See also mnt_table_set_parser_errcb().
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
+{
+ return __mnt_table_parse_mtab(tb, filename, NULL);
+}