parallel directory operations
Subsystems (2)
RFC 1/1 parallel directory operations
hi all!
this time linux can't perform many operations in the single directory. following patches are intended to solve this limitation. locking is broken into two stages: at first we protect dcache locking 'part of directory' using hash, at second (inside ext3) we protect htree structure. in both cases I use dynamic locks. there are several know issues to be solved yet (say, this patches don't let several renames in single dir).
Designed by Peter Braam.
simple benchmarks:
creation of 500K files by two processes:
before: 1m41.744s after: 1m28.837s
creation of 250K files by two processes:
before: 0m28.913s after: 0m20.851s
creation of 500K hardlinks by two processes:
before: 1m3.126s after: 0m48.669s
creation of 250K hardlinks by two processes:
before: 0m17.874s after: 0m10.427s
I would to like to see any comments/suggestions.
with best regards, Alex
dynamic locks. supports exclusive and shared locks. exclusive lock may be taken several times by first owner.
include/linux/dynlocks.h new file +35 -0
@@ -0,0 +1,35 @@ +#ifndef _LINUX_DYNLOCKS_H +#define _LINUX_DYNLOCKS_H + +#include <linux/list.h> +#include <linux/wait.h> +#include <linux/slab.h> +#include <linux/sched.h> + +struct dynlock_member { +struct list_head dl_list; +unsigned long dl_value;/* lock value */ +int dl_refcount;/* number of users */ +int dl_readers; +int dl_writers; +int dl_pid;/* holder of the lock */ +wait_queue_head_t dl_wait; +}; + +/* +* lock's namespace: +* - list of locks +* - lock to protect this list +*/ +struct dynlock { +struct list_head dl_list; +spinlock_t dl_list_lock; +}; + +void dynlock_init (struct dynlock *dl); +void *dynlock_lock (struct dynlock *dl,unsigned long value,int rw,int gfp); +void dynlock_unlock (struct dynlock *dl,void *lock); + + +#endif +
lib/dynlocks.c new file +150 -0
150 lines not on this page · raw message
lib/Makefile renamed from lib/Makefile~dynamic-locks +1 -1
@@ -5,7 +5,7 @@ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ - kobject.o idr.o + kobject.o idr.o dynlocks.o lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
_
support for parallel directory operations for VFS
fs/namei.c renamed from fs/namei.c~vfs-pdirops +93 -39
344 lines not on this page · raw message
include/linux/fs.h renamed from include/linux/fs.h~vfs-pdirops +4 -0
@@ -19,6 +19,7 @@#include <linux/cache.h> #include <linux/radix-tree.h> #include <linux/kobject.h> +#include <linux/dynlocks.h> #include <asm/atomic.h> struct iovec ;
@@ -136,6 +137,7 @@ extern int leases_enable, dir_notify_ena#define S_DEAD 32/* removed, but still open directory */ #define S_NOQUOTA 64/* Inode is not counted to quota */ #define S_DIRSYNC 128/* Directory modifications are synchronous */ +#define S_PDIROPS 256/* Parallel directory operations */ /* * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -167,6 +169,7 @@ extern int leases_enable, dir_notify_ena#define IS_NODIRATIME (inode) __IS_FLG(inode, MS_NODIRATIME)#define IS_POSIXACL (inode) __IS_FLG(inode, MS_POSIXACL)#define IS_ONE_SECOND (inode) __IS_FLG(inode, MS_ONE_SECOND) +#define IS_PDIROPS (inode) __IS_FLG(inode, S_PDIROPS)#define IS_DEADDIR (inode) ((inode)->i_flags & S_DEAD)
@@ -396,6 +399,7 @@ struct inode {atomic_t i_writecount;void *i_security;__u32 i_generation; +struct dynlock i_dcache_lock;/* for parallel directory ops */ union {void *generic_ip; } u;
include/linux/namei.h renamed from include/linux/namei.h~vfs-pdirops +3 -2
@@ -11,6 +11,7 @@ struct nameidata {struct qstr last;unsigned int flags;int last_type; +void *lock; };/*
@@ -49,7 +50,7 @@ extern struct dentry * lookup_hash(strucextern int follow_down (struct vfsmount **,struct dentry **);extern int follow_up (struct vfsmount **,struct dentry **); -extern struct dentry *lock_rename (struct dentry *,struct dentry *); -extern void unlock_rename (struct dentry *,struct dentry *); +extern struct dentry *lock_rename (struct nameidata *,struct nameidata *); +extern void unlock_rename (struct nameidata *,struct nameidata *);#endif /* _LINUX_NAMEI_H */
fs/inode.c renamed from fs/inode.c~vfs-pdirops +2 -0
@@ -19,6 +19,7 @@#include <linux/swap.h> #include <linux/security.h> #include <linux/cdev.h> +#include <linux/dynlocks.h> /* * This is needed for the following functions:
@@ -149,6 +150,7 @@ static struct inode *alloc_inode(struct mapping->backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;memset (&inode->u,0 ,sizeof (inode->u)); inode->i_mapping = mapping; +dynlock_init (&inode->i_dcache_lock); }return inode; }
_
parallel directory operations for EXT3.
htree consists of index blocks and leaves. leaves are protected against modifications and lookups. so, any process which wants to operate on some leaf have to lock this leaf. in order to decrease lock collisions while splitting we use bit-based spinlock to protect index blocks. this mean we can't sleep in the middle of index block modification and we have to make modifications in strict order, so that any user walking through the htree will not lose any leaf and will not select wrong leaf.
fs/ext3/namei.c renamed from fs/ext3/namei.c~ext3-pdirops +495 -122
1,134 lines not on this page · raw message
fs/ext3/super.c renamed from fs/ext3/super.c~ext3-pdirops +9 -0
@@ -504,6 +504,9 @@ static struct inode *ext3_alloc_inode(st ei->i_default_acl =EXT3_ACL_NOT_CACHED ;#endif ei->vfs_inode.i_version =1 ; +dynlock_init (&ei->i_htree_lock); +sema_init (&ei->i_append_sem,1 ); +sema_init (&ei->i_rename_sem,1 );return &ei->vfs_inode; }
@@ -712,6 +715,8 @@ static int parse_options (char * optionsreturn 0 ; } } +else if (!strcmp (this_char,"pdirops" )) +set_opt (sbi->s_mount_opt,PDIROPS );else if (!strcmp (this_char,"grpid" ) || !strcmp (this_char,"bsdgroups" ))set_opt (sbi->s_mount_opt,GRPID );
@@ -890,6 +895,10 @@ static int ext3_setup_super(struct superext3_check_blocks_bitmap (sb); ext3_check_inodes_bitmap (sb); } +#endif +#ifdef S_PDIROPS +if (test_opt (sb,PDIROPS )) + sb->s_flags |=S_PDIROPS ;#endif setup_ro_after (sb);return res;
include/linux/ext3_fs.h renamed from include/linux/ext3_fs.h~ext3-pdirops +1 -0
@@ -312,6 +312,7 @@ struct ext3_inode {/* * Mount flags */ +#define EXT3_MOUNT_PDIROPS 0x800000/* Parallel dir operations */ #define EXT3_MOUNT_CHECK 0x0001/* Do mount-time checks */ #define EXT3_MOUNT_OLDALLOC 0x0002/* Don't use the new Orlov allocator */ #define EXT3_MOUNT_GRPID 0x0004/* Create files with directory's group */
include/linux/ext3_fs_i.h renamed from include/linux/ext3_fs_i.h~ext3-pdirops +6 -0
@@ -17,6 +17,7 @@#define _LINUX_EXT3_FS_I#include <linux/rwsem.h> +#include <linux/dynlocks.h> /* * second extended file system inode data in memory
@@ -98,6 +99,11 @@ struct ext3_inode_info {*/ struct rw_semaphore truncate_sem;struct inode vfs_inode; + +/* following fields for parallel directory operations -bzzz */ +struct dynlock i_htree_lock; +struct semaphore i_append_sem; + struct semaphore i_rename_sem; };#endif /* _LINUX_EXT3_FS_I */
_
Quoted 1 line · Alex Tomas
I use dynamic locks
dynamic locks doesn't really look like a name that matches what it does.. how about "spinarecuphore" ?
Quoted 4 lines · Alex Tomas
I would to like to see any comments/suggestions.
dynamic locks. supports exclusive and shared locks. exclusive lock may be taken several times by first owner.
Yuck. It spins, it sleeps, it can be acquired recursively by the same process. Ugly stuff.
Signature · 3 lines
"It's not Hollywood. War is real, war is primarily not about defeat or victory, it is about death. I've seen thousands and thousands of dead bodies. Do you think I want to have an academic debate on this subject?" -- Robert Fisk
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Matthew Wilcox (MW) writes:
Quoted 4 lines · Alex Tomas
Quoted 4 lines
I would to like to see any comments/suggestions.
dynamic locks. supports exclusive and shared locks. exclusive lock may be taken several times by first owner.
MW> Yuck. It spins, it sleeps, it can be acquired recursively by the same MW> process. Ugly stuff.
it allows to simplify rename case very much