d3ef3d7351
This patch speeds up lmbench lat_mmap test by about 8%. lat_mmap is set up basically to mmap a 64MB file on tmpfs, fault in its pages, then unmap it. A microbenchmark yes, but it exercises some important paths in the mm. Before: avg = 501.9 std = 14.7773 After: avg = 462.286 std = 5.46106 (50 runs of each, stddev gives a reasonable confidence, but there is quite a bit of variation there still) It does this by removing the complex per-cpu locking and counter-cache and replaces it with a percpu counter in struct vfsmount. This makes the code much simpler, and avoids spinlocks (although the msync is still pretty costly, unfortunately). It results in about 900 bytes smaller code too. It does increase the size of a vfsmount, however. It should also give a speedup on large systems if CPUs are frequently operating on different mounts (because the existing scheme has to operate on an atomic in the struct vfsmount when switching between mounts). But I'm most interested in the single threaded path performance for the moment. [AV: minor cleanup] Cc: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
125 lines
3.5 KiB
C
125 lines
3.5 KiB
C
/*
|
|
*
|
|
* Definitions for mount interface. This describes the in the kernel build
|
|
* linkedlist with mounted filesystems.
|
|
*
|
|
* Author: Marco van Wieringen <mvw@planets.elm.net>
|
|
*
|
|
*/
|
|
#ifndef _LINUX_MOUNT_H
|
|
#define _LINUX_MOUNT_H
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/list.h>
|
|
#include <linux/nodemask.h>
|
|
#include <linux/spinlock.h>
|
|
#include <asm/atomic.h>
|
|
|
|
struct super_block;
|
|
struct vfsmount;
|
|
struct dentry;
|
|
struct mnt_namespace;
|
|
|
|
#define MNT_NOSUID 0x01
|
|
#define MNT_NODEV 0x02
|
|
#define MNT_NOEXEC 0x04
|
|
#define MNT_NOATIME 0x08
|
|
#define MNT_NODIRATIME 0x10
|
|
#define MNT_RELATIME 0x20
|
|
#define MNT_READONLY 0x40 /* does the user want this to be r/o? */
|
|
#define MNT_STRICTATIME 0x80
|
|
|
|
#define MNT_SHRINKABLE 0x100
|
|
#define MNT_WRITE_HOLD 0x200
|
|
|
|
#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */
|
|
#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */
|
|
#define MNT_PNODE_MASK 0x3000 /* propagation flag mask */
|
|
|
|
struct vfsmount {
|
|
struct list_head mnt_hash;
|
|
struct vfsmount *mnt_parent; /* fs we are mounted on */
|
|
struct dentry *mnt_mountpoint; /* dentry of mountpoint */
|
|
struct dentry *mnt_root; /* root of the mounted tree */
|
|
struct super_block *mnt_sb; /* pointer to superblock */
|
|
struct list_head mnt_mounts; /* list of children, anchored here */
|
|
struct list_head mnt_child; /* and going through their mnt_child */
|
|
int mnt_flags;
|
|
/* 4 bytes hole on 64bits arches */
|
|
const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
|
|
struct list_head mnt_list;
|
|
struct list_head mnt_expire; /* link in fs-specific expiry list */
|
|
struct list_head mnt_share; /* circular list of shared mounts */
|
|
struct list_head mnt_slave_list;/* list of slave mounts */
|
|
struct list_head mnt_slave; /* slave list entry */
|
|
struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
|
|
struct mnt_namespace *mnt_ns; /* containing namespace */
|
|
int mnt_id; /* mount identifier */
|
|
int mnt_group_id; /* peer group identifier */
|
|
/*
|
|
* We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
|
|
* to let these frequently modified fields in a separate cache line
|
|
* (so that reads of mnt_flags wont ping-pong on SMP machines)
|
|
*/
|
|
atomic_t mnt_count;
|
|
int mnt_expiry_mark; /* true if marked for expiry */
|
|
int mnt_pinned;
|
|
int mnt_ghosts;
|
|
#ifdef CONFIG_SMP
|
|
int *mnt_writers;
|
|
#else
|
|
int mnt_writers;
|
|
#endif
|
|
};
|
|
|
|
static inline int *get_mnt_writers_ptr(struct vfsmount *mnt)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
return mnt->mnt_writers;
|
|
#else
|
|
return &mnt->mnt_writers;
|
|
#endif
|
|
}
|
|
|
|
static inline struct vfsmount *mntget(struct vfsmount *mnt)
|
|
{
|
|
if (mnt)
|
|
atomic_inc(&mnt->mnt_count);
|
|
return mnt;
|
|
}
|
|
|
|
extern int mnt_want_write(struct vfsmount *mnt);
|
|
extern void mnt_drop_write(struct vfsmount *mnt);
|
|
extern void mntput_no_expire(struct vfsmount *mnt);
|
|
extern void mnt_pin(struct vfsmount *mnt);
|
|
extern void mnt_unpin(struct vfsmount *mnt);
|
|
extern int __mnt_is_readonly(struct vfsmount *mnt);
|
|
|
|
static inline void mntput(struct vfsmount *mnt)
|
|
{
|
|
if (mnt) {
|
|
mnt->mnt_expiry_mark = 0;
|
|
mntput_no_expire(mnt);
|
|
}
|
|
}
|
|
|
|
extern struct vfsmount *do_kern_mount(const char *fstype, int flags,
|
|
const char *name, void *data);
|
|
|
|
struct file_system_type;
|
|
extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
|
|
int flags, const char *name,
|
|
void *data);
|
|
|
|
struct nameidata;
|
|
|
|
struct path;
|
|
extern int do_add_mount(struct vfsmount *newmnt, struct path *path,
|
|
int mnt_flags, struct list_head *fslist);
|
|
|
|
extern void mark_mounts_for_expiry(struct list_head *mounts);
|
|
|
|
extern spinlock_t vfsmount_lock;
|
|
extern dev_t name_to_dev_t(char *name);
|
|
|
|
#endif /* _LINUX_MOUNT_H */
|