diff -durN -X dontdiff linux/Makefile linux-2.4.20-preempt-mutex-pi2/Makefile --- linux/Makefile 2003-01-11 01:03:05.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/Makefile 2003-01-14 17:18:14.000000000 +0100 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 20 -EXTRAVERSION = +EXTRAVERSION = -preempt-mutex-pi2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -durN -X dontdiff linux/arch/i386/config.in linux-2.4.20-preempt-mutex-pi2/arch/i386/config.in --- linux/arch/i386/config.in 2003-01-10 02:49:27.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/arch/i386/config.in 2003-01-14 17:18:14.000000000 +0100 @@ -207,6 +207,12 @@ bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP bool 'Preemptible Kernel' CONFIG_PREEMPT +if [ "$CONFIG_PREEMPT" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'dcache mutex' CONFIG_DCACHE_MTX +fi +if [ "$CONFIG_PREEMPT" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'mutex priority inheritance' CONFIG_MTX_PI +fi if [ "$CONFIG_SMP" != "y" ]; then bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC diff -durN -X dontdiff linux/arch/i386/lib/dec_and_lock.c linux-2.4.20-preempt-mutex-pi2/arch/i386/lib/dec_and_lock.c --- linux/arch/i386/lib/dec_and_lock.c 2003-01-10 02:49:27.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/arch/i386/lib/dec_and_lock.c 2003-01-14 17:18:14.000000000 +0100 @@ -10,6 +10,7 @@ #include #include #include +#include int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { @@ -39,3 +40,14 @@ spin_unlock(lock); return 0; } + +#ifdef CONFIG_PREEMPT +int atomic_dec_and_mutex_lock(atomic_t *atomic, p_mutex_t *mtx) +{ + p_mutex_down(mtx); + if (atomic_dec_and_test(atomic)) + return 1; + p_mutex_up(mtx); + return 0; +} +#endif diff -durN -X dontdiff linux/drivers/hotplug/pci_hotplug_core.c linux-2.4.20-preempt-mutex-pi2/drivers/hotplug/pci_hotplug_core.c --- linux/drivers/hotplug/pci_hotplug_core.c 2003-01-10 02:36:16.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/drivers/hotplug/pci_hotplug_core.c 2003-01-14 17:18:14.000000000 +0100 @@ -193,17 +193,17 @@ { struct list_head *list; - spin_lock(&dcache_lock); + lock_dcache(); list_for_each(list, &dentry->d_subdirs) { struct dentry *de = list_entry(list, struct dentry, d_child); if (pcihpfs_positive(de)) { - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; } } - spin_unlock(&dcache_lock); + unlock_dcache(); return 1; } diff -durN -X dontdiff linux/fs/affs/amigaffs.c linux-2.4.20-preempt-mutex-pi2/fs/affs/amigaffs.c --- linux/fs/affs/amigaffs.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/affs/amigaffs.c 2003-01-14 17:18:14.000000000 +0100 @@ -134,7 +134,7 @@ void *data = dentry->d_fsdata; struct list_head *head, *next; - spin_lock(&dcache_lock); + lock_dcache(); head = &inode->i_dentry; next = head->next; while (next != head) { @@ -145,7 +145,7 @@ } next = next->next; } - spin_unlock(&dcache_lock); + unlock_dcache(); } diff -durN -X dontdiff linux/fs/autofs4/expire.c linux-2.4.20-preempt-mutex-pi2/fs/autofs4/expire.c --- linux/fs/autofs4/expire.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/autofs4/expire.c 2003-01-14 17:18:14.000000000 +0100 @@ -164,7 +164,7 @@ timeout = sbi->exp_timeout; - spin_lock(&dcache_lock); + lock_dcache(); for(tmp = root->d_subdirs.next; tmp != &root->d_subdirs; tmp = tmp->next) { @@ -203,12 +203,12 @@ list_del(&root->d_subdirs); list_add(&root->d_subdirs, &dentry->d_child); dget(dentry); - spin_unlock(&dcache_lock); + unlock_dcache(); return dentry; } } - spin_unlock(&dcache_lock); + unlock_dcache(); return NULL; } diff -durN -X dontdiff linux/fs/autofs4/root.c linux-2.4.20-preempt-mutex-pi2/fs/autofs4/root.c --- linux/fs/autofs4/root.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/autofs4/root.c 2003-01-14 17:18:14.000000000 +0100 @@ -118,15 +118,15 @@ /* If this is an unused directory that isn't a mount point, bitch at the daemon and fix it in user space */ - spin_lock(&dcache_lock); + lock_dcache(); if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { DPRINTK(("try_to_fill_entry: mounting existing dir\n")); - spin_unlock(&dcache_lock); + unlock_dcache(); return autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT) == 0; } - spin_unlock(&dcache_lock); + unlock_dcache(); /* We don't update the usages for the autofs daemon itself, this is necessary for recursive autofs mounts */ @@ -166,19 +166,19 @@ ino = autofs4_dentry_ino(dentry); /* Check for a non-mountpoint directory with no contents */ - spin_lock(&dcache_lock); + lock_dcache(); if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { DPRINTK(("autofs_root_revalidate: dentry=%p %.*s, emptydir\n", dentry, dentry->d_name.len, dentry->d_name.name)); - spin_unlock(&dcache_lock); + unlock_dcache(); if (oz_mode) return 1; else return try_to_fill_dentry(dentry, dir->i_sb, sbi); } - spin_unlock(&dcache_lock); + unlock_dcache(); /* Update the usage list */ if (!oz_mode) @@ -397,13 +397,13 @@ if (!autofs4_oz_mode(sbi)) return -EACCES; - spin_lock(&dcache_lock); + lock_dcache(); if (!list_empty(&dentry->d_subdirs)) { - spin_unlock(&dcache_lock); + unlock_dcache(); return -ENOTEMPTY; } list_del_init(&dentry->d_hash); - spin_unlock(&dcache_lock); + unlock_dcache(); dput(ino->dentry); diff -durN -X dontdiff linux/fs/coda/cache.c linux-2.4.20-preempt-mutex-pi2/fs/coda/cache.c --- linux/fs/coda/cache.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/coda/cache.c 2003-01-14 17:18:14.000000000 +0100 @@ -95,7 +95,7 @@ struct list_head *child; struct dentry *de; - spin_lock(&dcache_lock); + lock_dcache(); list_for_each(child, &parent->d_subdirs) { de = list_entry(child, struct dentry, d_child); @@ -107,7 +107,7 @@ de->d_parent->d_name.len, de->d_parent->d_name.name); coda_flag_inode(de->d_inode, flag); } - spin_unlock(&dcache_lock); + unlock_dcache(); return; } diff -durN -X dontdiff linux/fs/dcache.c linux-2.4.20-preempt-mutex-pi2/fs/dcache.c --- linux/fs/dcache.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/dcache.c 2003-01-14 17:18:14.000000000 +0100 @@ -23,13 +23,19 @@ #include #include #include +#include #include #define DCACHE_PARANOIA 1 /* #define DCACHE_DEBUG 1 */ -spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_DCACHE_MTX +DECLARE_P_MUTEX(dcache_mtx); +#else +spinlock_t dcache_mtx __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +#endif + /* Right now the dcache depends on the kernel lock */ #define check_lock() if (!kernel_locked()) BUG() @@ -77,13 +83,13 @@ if (inode) { dentry->d_inode = NULL; list_del_init(&dentry->d_alias); - spin_unlock(&dcache_lock); + unlock_dcache(); if (dentry->d_op && dentry->d_op->d_iput) dentry->d_op->d_iput(dentry, inode); else iput(inode); } else - spin_unlock(&dcache_lock); + unlock_dcache(); } /* @@ -121,7 +127,7 @@ return; repeat: - if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) + if (!atomic_dec_and_lock_dcache(&dentry->d_count)) return; /* dput on a free dentry? */ @@ -139,7 +145,7 @@ goto kill_it; list_add(&dentry->d_lru, &dentry_unused); dentry_stat.nr_unused++; - spin_unlock(&dcache_lock); + unlock_dcache(); return; unhash_it: @@ -176,9 +182,9 @@ /* * If it's already been dropped, return OK. */ - spin_lock(&dcache_lock); + lock_dcache(); if (list_empty(&dentry->d_hash)) { - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; } /* @@ -186,9 +192,9 @@ * to get rid of unused child entries. */ if (!list_empty(&dentry->d_subdirs)) { - spin_unlock(&dcache_lock); + unlock_dcache(); shrink_dcache_parent(dentry); - spin_lock(&dcache_lock); + lock_dcache(); } /* @@ -203,13 +209,13 @@ */ if (atomic_read(&dentry->d_count) > 1) { if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { - spin_unlock(&dcache_lock); + unlock_dcache(); return -EBUSY; } } list_del_init(&dentry->d_hash); - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; } @@ -245,7 +251,7 @@ struct list_head *head, *next, *tmp; struct dentry *alias; - spin_lock(&dcache_lock); + lock_dcache(); head = &inode->i_dentry; next = inode->i_dentry.next; while (next != head) { @@ -254,11 +260,11 @@ alias = list_entry(tmp, struct dentry, d_alias); if (!list_empty(&alias->d_hash)) { __dget_locked(alias); - spin_unlock(&dcache_lock); + unlock_dcache(); return alias; } } - spin_unlock(&dcache_lock); + unlock_dcache(); return NULL; } @@ -270,19 +276,19 @@ { struct list_head *tmp, *head = &inode->i_dentry; restart: - spin_lock(&dcache_lock); + lock_dcache(); tmp = head; while ((tmp = tmp->next) != head) { struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); if (!atomic_read(&dentry->d_count)) { __dget_locked(dentry); - spin_unlock(&dcache_lock); + unlock_dcache(); d_drop(dentry); dput(dentry); goto restart; } } - spin_unlock(&dcache_lock); + unlock_dcache(); } /* @@ -302,7 +308,7 @@ d_free(dentry); if (parent != dentry) dput(parent); - spin_lock(&dcache_lock); + lock_dcache(); } /** @@ -320,7 +326,7 @@ void prune_dcache(int count) { - spin_lock(&dcache_lock); + lock_dcache(); for (;;) { struct dentry *dentry; struct list_head *tmp; @@ -348,7 +354,7 @@ if (!--count) break; } - spin_unlock(&dcache_lock); + unlock_dcache(); } /* @@ -382,7 +388,7 @@ * Pass one ... move the dentries for the specified * superblock to the most recent end of the unused list. */ - spin_lock(&dcache_lock); + lock_dcache(); next = dentry_unused.next; while (next != &dentry_unused) { tmp = next; @@ -412,7 +418,7 @@ prune_one_dentry(dentry); goto repeat; } - spin_unlock(&dcache_lock); + unlock_dcache(); } /* @@ -434,7 +440,7 @@ struct dentry *this_parent = parent; struct list_head *next; - spin_lock(&dcache_lock); + lock_dcache(); if (d_mountpoint(parent)) goto positive; repeat: @@ -460,10 +466,10 @@ this_parent = this_parent->d_parent; goto resume; } - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; /* No mount points found in tree */ positive: - spin_unlock(&dcache_lock); + unlock_dcache(); return 1; } @@ -480,7 +486,7 @@ struct list_head *next; int found = 0; - spin_lock(&dcache_lock); + lock_dcache(); repeat: next = this_parent->d_subdirs.next; resume: @@ -517,7 +523,7 @@ #endif goto resume; } - spin_unlock(&dcache_lock); + unlock_dcache(); return found; } @@ -623,9 +629,9 @@ if (parent) { dentry->d_parent = dget(parent); dentry->d_sb = parent->d_sb; - spin_lock(&dcache_lock); + lock_dcache(); list_add(&dentry->d_child, &parent->d_subdirs); - spin_unlock(&dcache_lock); + unlock_dcache(); } else INIT_LIST_HEAD(&dentry->d_child); @@ -651,11 +657,11 @@ void d_instantiate(struct dentry *entry, struct inode * inode) { if (!list_empty(&entry->d_alias)) BUG(); - spin_lock(&dcache_lock); + lock_dcache(); if (inode) list_add(&entry->d_alias, &inode->i_dentry); entry->d_inode = inode; - spin_unlock(&dcache_lock); + unlock_dcache(); } /** @@ -708,7 +714,7 @@ struct list_head *head = d_hash(parent,hash); struct list_head *tmp; - spin_lock(&dcache_lock); + lock_dcache(); tmp = head->next; for (;;) { struct dentry * dentry = list_entry(tmp, struct dentry, d_hash); @@ -730,10 +736,10 @@ } __dget_locked(dentry); dentry->d_vfs_flags |= DCACHE_REFERENCED; - spin_unlock(&dcache_lock); + unlock_dcache(); return dentry; } - spin_unlock(&dcache_lock); + unlock_dcache(); return NULL; } @@ -769,16 +775,16 @@ if (dentry->d_parent != dparent) goto out; - spin_lock(&dcache_lock); + lock_dcache(); lhp = base = d_hash(dparent, dentry->d_name.hash); while ((lhp = lhp->next) != base) { if (dentry == list_entry(lhp, struct dentry, d_hash)) { __dget_locked(dentry); - spin_unlock(&dcache_lock); + unlock_dcache(); return 1; } } - spin_unlock(&dcache_lock); + unlock_dcache(); out: return 0; } @@ -809,12 +815,12 @@ /* * Are we the only user? */ - spin_lock(&dcache_lock); + lock_dcache(); if (atomic_read(&dentry->d_count) == 1) { dentry_iput(dentry); return; } - spin_unlock(&dcache_lock); + unlock_dcache(); /* * If not, just drop the dentry and let dput @@ -834,9 +840,9 @@ { struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash); if (!list_empty(&entry->d_hash)) BUG(); - spin_lock(&dcache_lock); + lock_dcache(); list_add(&entry->d_hash, list); - spin_unlock(&dcache_lock); + unlock_dcache(); } #define do_switch(x,y) do { \ @@ -902,7 +908,7 @@ if (!dentry->d_inode) printk(KERN_WARNING "VFS: moving negative dcache entry\n"); - spin_lock(&dcache_lock); + lock_dcache(); /* Move the dentry to the target hash queue */ list_del(&dentry->d_hash); list_add(&dentry->d_hash, &target->d_hash); @@ -922,7 +928,7 @@ /* And add them back to the (new) parent lists */ list_add(&target->d_child, &target->d_parent->d_subdirs); list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); - spin_unlock(&dcache_lock); + unlock_dcache(); } /** @@ -1032,13 +1038,13 @@ error = -ENOENT; /* Has the current directory has been unlinked? */ - spin_lock(&dcache_lock); + lock_dcache(); if (pwd->d_parent == pwd || !list_empty(&pwd->d_hash)) { unsigned long len; char * cwd; cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); - spin_unlock(&dcache_lock); + unlock_dcache(); error = -ERANGE; len = PAGE_SIZE + page - cwd; @@ -1048,7 +1054,7 @@ error = -EFAULT; } } else - spin_unlock(&dcache_lock); + unlock_dcache(); dput(pwd); mntput(pwdmnt); dput(root); @@ -1096,7 +1102,7 @@ struct dentry *this_parent = root; struct list_head *next; - spin_lock(&dcache_lock); + lock_dcache(); repeat: next = this_parent->d_subdirs.next; resume: @@ -1118,7 +1124,7 @@ this_parent = this_parent->d_parent; goto resume; } - spin_unlock(&dcache_lock); + unlock_dcache(); } /** diff -durN -X dontdiff linux/fs/devfs/base.c linux-2.4.20-preempt-mutex-pi2/fs/devfs/base.c --- linux/fs/devfs/base.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/devfs/base.c 2003-01-14 17:18:14.000000000 +0100 @@ -1389,10 +1389,10 @@ { struct dentry *dentry = de->inode.dentry; - if (!dentry) return; - spin_lock (&dcache_lock); + if (!dentry) return; + lock_dcache(); dget_locked (dentry); - spin_unlock (&dcache_lock); + unlock_dcache(); /* Forcefully remove the inode */ if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0; d_drop (dentry); diff -durN -X dontdiff linux/fs/fat/inode.c linux-2.4.20-preempt-mutex-pi2/fs/fat/inode.c --- linux/fs/fat/inode.c 2003-01-10 02:36:07.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/fat/inode.c 2003-01-14 17:18:14.000000000 +0100 @@ -485,18 +485,18 @@ * well-connected, but it is easiest to just copy the * code. */ - spin_lock(&dcache_lock); + lock_dcache(); for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { result = list_entry(lp,struct dentry, d_alias); if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { dget_locked(result); result->d_vfs_flags |= DCACHE_REFERENCED; - spin_unlock(&dcache_lock); + unlock_dcache(); iput(inode); return result; } } - spin_unlock(&dcache_lock); + unlock_dcache(); result = d_alloc_root(inode); if (result == NULL) { iput(inode); diff -durN -X dontdiff linux/fs/intermezzo/dcache.c linux-2.4.20-preempt-mutex-pi2/fs/intermezzo/dcache.c --- linux/fs/intermezzo/dcache.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/intermezzo/dcache.c 2003-01-14 17:18:14.000000000 +0100 @@ -185,7 +185,7 @@ struct dentry *tmp_dentry; /* Search through the alias list for dentries with d_fsdata */ - spin_lock(&dcache_lock); + lock_dcache(); head = &inode->i_dentry; next = inode->i_dentry.next; while (next != head) { @@ -193,11 +193,11 @@ next = tmp->next; tmp_dentry = list_entry(tmp, struct dentry, d_alias); if (!presto_d2d(tmp_dentry)) { - spin_unlock(&dcache_lock); + unlock_dcache(); return presto_d2d(tmp_dentry); } } - spin_unlock(&dcache_lock); + unlock_dcache(); return NULL; } @@ -214,7 +214,7 @@ dentry->d_fsdata = dd; /* Now set d_fsdata for all dentries in the alias list. */ - spin_lock(&dcache_lock); + lock_dcache(); head = &inode->i_dentry; next = inode->i_dentry.next; while (next != head) { @@ -226,7 +226,7 @@ tmp_dentry->d_fsdata = dd; } } - spin_unlock(&dcache_lock); + unlock_dcache(); return; } diff -durN -X dontdiff linux/fs/namei.c linux-2.4.20-preempt-mutex-pi2/fs/namei.c --- linux/fs/namei.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/namei.c 2003-01-14 17:18:14.000000000 +0100 @@ -358,15 +358,15 @@ { struct vfsmount *parent; struct dentry *dentry; - spin_lock(&dcache_lock); + lock_dcache(); parent=(*mnt)->mnt_parent; if (parent == *mnt) { - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; } mntget(parent); dentry=dget((*mnt)->mnt_mountpoint); - spin_unlock(&dcache_lock); + unlock_dcache(); dput(*base); *base = dentry; mntput(*mnt); @@ -383,17 +383,17 @@ { struct vfsmount *mounted; - spin_lock(&dcache_lock); + lock_dcache(); mounted = lookup_mnt(*mnt, *dentry); if (mounted) { *mnt = mntget(mounted); - spin_unlock(&dcache_lock); + unlock_dcache(); dput(*dentry); mntput(mounted->mnt_parent); *dentry = dget(mounted->mnt_root); return 1; } - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; } @@ -414,22 +414,22 @@ break; } read_unlock(¤t->fs->lock); - spin_lock(&dcache_lock); + lock_dcache(); if (nd->dentry != nd->mnt->mnt_root) { dentry = dget(nd->dentry->d_parent); - spin_unlock(&dcache_lock); + unlock_dcache(); dput(nd->dentry); nd->dentry = dentry; break; } parent=nd->mnt->mnt_parent; if (parent == nd->mnt) { - spin_unlock(&dcache_lock); + unlock_dcache(); break; } mntget(parent); dentry=dget(nd->mnt->mnt_mountpoint); - spin_unlock(&dcache_lock); + unlock_dcache(); dput(nd->dentry); nd->dentry = dentry; mntput(nd->mnt); @@ -1377,18 +1377,18 @@ static void d_unhash(struct dentry *dentry) { dget(dentry); - spin_lock(&dcache_lock); + lock_dcache(); switch (atomic_read(&dentry->d_count)) { default: - spin_unlock(&dcache_lock); + unlock_dcache(); shrink_dcache_parent(dentry); - spin_lock(&dcache_lock); + lock_dcache(); if (atomic_read(&dentry->d_count) != 2) break; case 2: list_del_init(&dentry->d_hash); } - spin_unlock(&dcache_lock); + unlock_dcache(); } int vfs_rmdir(struct inode *dir, struct dentry *dentry) diff -durN -X dontdiff linux/fs/namespace.c linux-2.4.20-preempt-mutex-pi2/fs/namespace.c --- linux/fs/namespace.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/namespace.c 2003-01-14 17:18:14.000000000 +0100 @@ -88,10 +88,10 @@ static int check_mnt(struct vfsmount *mnt) { - spin_lock(&dcache_lock); + lock_dcache(); while (mnt->mnt_parent != mnt) mnt = mnt->mnt_parent; - spin_unlock(&dcache_lock); + unlock_dcache(); return mnt == current->namespace->root; } @@ -271,15 +271,15 @@ mnt = list_entry(kill.next, struct vfsmount, mnt_list); list_del_init(&mnt->mnt_list); if (mnt->mnt_parent == mnt) { - spin_unlock(&dcache_lock); + unlock_dcache(); } else { struct nameidata old_nd; detach_mnt(mnt, &old_nd); - spin_unlock(&dcache_lock); + unlock_dcache(); path_release(&old_nd); } mntput(mnt); - spin_lock(&dcache_lock); + lock_dcache(); } } @@ -328,16 +328,16 @@ } down_write(¤t->namespace->sem); - spin_lock(&dcache_lock); - + lock_dcache(); + if (atomic_read(&sb->s_active) == 1) { /* last instance - try to be smart */ - spin_unlock(&dcache_lock); + unlock_dcache(); lock_kernel(); DQUOT_OFF(sb); acct_auto_close(sb->s_dev); unlock_kernel(); - spin_lock(&dcache_lock); + lock_dcache(); } retval = -EBUSY; if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { @@ -345,7 +345,7 @@ umount_tree(mnt); retval = 0; } - spin_unlock(&dcache_lock); + unlock_dcache(); up_write(¤t->namespace->sem); return retval; } @@ -433,17 +433,17 @@ q = clone_mnt(p, p->mnt_root); if (!q) goto Enomem; - spin_lock(&dcache_lock); + lock_dcache(); list_add_tail(&q->mnt_list, &res->mnt_list); attach_mnt(q, &nd); - spin_unlock(&dcache_lock); + unlock_dcache(); } return res; Enomem: if (res) { - spin_lock(&dcache_lock); + lock_dcache(); umount_tree(res); - spin_unlock(&dcache_lock); + unlock_dcache(); } return NULL; } @@ -463,7 +463,7 @@ if (IS_DEADDIR(nd->dentry->d_inode)) goto out_unlock; - spin_lock(&dcache_lock); + lock_dcache(); if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) { struct list_head head; attach_mnt(mnt, nd); @@ -472,7 +472,7 @@ mntget(mnt); err = 0; } - spin_unlock(&dcache_lock); + unlock_dcache(); out_unlock: up(&nd->dentry->d_inode->i_zombie); return err; @@ -507,9 +507,9 @@ if (mnt) { err = graft_tree(mnt, nd); if (err) { - spin_lock(&dcache_lock); + lock_dcache(); umount_tree(mnt); - spin_unlock(&dcache_lock); + unlock_dcache(); } else mntput(mnt); } @@ -572,7 +572,7 @@ if (IS_DEADDIR(nd->dentry->d_inode)) goto out1; - spin_lock(&dcache_lock); + lock_dcache(); if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry)) goto out2; @@ -596,7 +596,7 @@ detach_mnt(old_nd.mnt, &parent_nd); attach_mnt(old_nd.mnt, nd); out2: - spin_unlock(&dcache_lock); + unlock_dcache(); out1: up(&nd->dentry->d_inode->i_zombie); out: @@ -772,9 +772,9 @@ down_write(&tsk->namespace->sem); /* First pass: copy the tree topology */ new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root); - spin_lock(&dcache_lock); + lock_dcache(); list_add_tail(&new_ns->list, &new_ns->root->mnt_list); - spin_unlock(&dcache_lock); + unlock_dcache(); /* Second pass: switch the tsk->fs->* elements */ if (fs) { @@ -944,7 +944,7 @@ if (new_nd.mnt->mnt_root != new_nd.dentry) goto out2; /* not a mountpoint */ tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */ - spin_lock(&dcache_lock); + lock_dcache(); if (tmp != new_nd.mnt) { for (;;) { if (tmp->mnt_parent == tmp) @@ -961,7 +961,7 @@ detach_mnt(user_nd.mnt, &root_parent); attach_mnt(user_nd.mnt, &old_nd); attach_mnt(new_nd.mnt, &root_parent); - spin_unlock(&dcache_lock); + unlock_dcache(); chroot_fs_refs(&user_nd, &new_nd); error = 0; path_release(&root_parent); @@ -977,7 +977,7 @@ unlock_kernel(); return error; out3: - spin_unlock(&dcache_lock); + unlock_dcache(); goto out2; } diff -durN -X dontdiff linux/fs/ncpfs/dir.c linux-2.4.20-preempt-mutex-pi2/fs/ncpfs/dir.c --- linux/fs/ncpfs/dir.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/ncpfs/dir.c 2003-01-14 17:18:14.000000000 +0100 @@ -352,7 +352,7 @@ } /* If a pointer is invalid, we search the dentry. */ - spin_lock(&dcache_lock); + lock_dcache(); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { dent = list_entry(next, struct dentry, d_child); @@ -361,12 +361,12 @@ dget_locked(dent); else dent = NULL; - spin_unlock(&dcache_lock); + unlock_dcache(); goto out; } next = next->next; } - spin_unlock(&dcache_lock); + unlock_dcache(); return NULL; out: diff -durN -X dontdiff linux/fs/ncpfs/ncplib_kernel.h linux-2.4.20-preempt-mutex-pi2/fs/ncpfs/ncplib_kernel.h --- linux/fs/ncpfs/ncplib_kernel.h 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/ncpfs/ncplib_kernel.h 2003-01-14 17:18:14.000000000 +0100 @@ -158,7 +158,7 @@ struct list_head *next; struct dentry *dentry; - spin_lock(&dcache_lock); + lock_dcache(); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { dentry = list_entry(next, struct dentry, d_child); @@ -170,7 +170,7 @@ next = next->next; } - spin_unlock(&dcache_lock); + unlock_dcache(); } static inline void @@ -180,7 +180,7 @@ struct list_head *next; struct dentry *dentry; - spin_lock(&dcache_lock); + lock_dcache(); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { dentry = list_entry(next, struct dentry, d_child); @@ -188,7 +188,7 @@ ncp_age_dentry(server, dentry); next = next->next; } - spin_unlock(&dcache_lock); + unlock_dcache(); } struct ncp_cache_head { diff -durN -X dontdiff linux/fs/nfsd/nfsfh.c linux-2.4.20-preempt-mutex-pi2/fs/nfsd/nfsfh.c --- linux/fs/nfsd/nfsfh.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/nfsd/nfsfh.c 2003-01-14 17:18:14.000000000 +0100 @@ -158,18 +158,18 @@ /* now to find a dentry. * If possible, get a well-connected one */ - spin_lock(&dcache_lock); + lock_dcache(); for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { result = list_entry(lp,struct dentry, d_alias); if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { dget_locked(result); result->d_vfs_flags |= DCACHE_REFERENCED; - spin_unlock(&dcache_lock); + unlock_dcache(); iput(inode); return result; } } - spin_unlock(&dcache_lock); + unlock_dcache(); result = d_alloc_root(inode); if (result == NULL) { iput(inode); @@ -225,10 +225,10 @@ /* tdentry will have been made a "child" of target (the parent of target) * make it an IS_ROOT instead */ - spin_lock(&dcache_lock); + lock_dcache(); list_del_init(&tdentry->d_child); tdentry->d_parent = tdentry; - spin_unlock(&dcache_lock); + unlock_dcache(); d_rehash(target); dput(tdentry); @@ -240,7 +240,7 @@ while (target) { target->d_flags &= ~DCACHE_NFSD_DISCONNECTED; parent = target; - spin_lock(&dcache_lock); + lock_dcache(); if (list_empty(&parent->d_subdirs)) target = NULL; else { @@ -253,7 +253,7 @@ parent->d_name.name, target->d_name.name); #endif } - spin_unlock(&dcache_lock); + unlock_dcache(); } } return 0; @@ -290,7 +290,7 @@ * else make a root dentry */ struct list_head *aliases = &tdentry->d_inode->i_dentry; - spin_lock(&dcache_lock); + lock_dcache(); if (aliases->next != aliases) { pdentry = list_entry(aliases->next, struct dentry, d_alias); if (pdentry == tdentry) @@ -299,7 +299,7 @@ pdentry = NULL; if (pdentry) dget_locked(pdentry); } - spin_unlock(&dcache_lock); + unlock_dcache(); if (pdentry == NULL) { pdentry = d_alloc_root(tdentry->d_inode); if (pdentry) { @@ -347,17 +347,17 @@ * parent by a lookup. In this case return that dentry. Caller must * notice and act accordingly */ - spin_lock(&dcache_lock); + lock_dcache(); list_for_each(lp, &child->d_inode->i_dentry) { struct dentry *tmp = list_entry(lp,struct dentry, d_alias); if (!list_empty(&tmp->d_hash) && tmp->d_parent == parent) { child = dget_locked(tmp); - spin_unlock(&dcache_lock); + unlock_dcache(); goto out; } } - spin_unlock(&dcache_lock); + unlock_dcache(); /* now we need that name. If there was an error getting it, now is th * time to bail out. diff -durN -X dontdiff linux/fs/proc/base.c linux-2.4.20-preempt-mutex-pi2/fs/proc/base.c --- linux/fs/proc/base.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/proc/base.c 2003-01-14 17:18:14.000000000 +0100 @@ -199,7 +199,7 @@ base = dget(current->fs->root); read_unlock(¤t->fs->lock); - spin_lock(&dcache_lock); + lock_dcache(); de = root; mnt = vfsmnt; @@ -212,7 +212,7 @@ if (!is_subdir(de, base)) goto out; - spin_unlock(&dcache_lock); + unlock_dcache(); exit: dput(base); @@ -221,7 +221,7 @@ mntput(mnt); return res; out: - spin_unlock(&dcache_lock); + unlock_dcache(); res = -EACCES; goto exit; } diff -durN -X dontdiff linux/fs/ramfs/inode.c linux-2.4.20-preempt-mutex-pi2/fs/ramfs/inode.c --- linux/fs/ramfs/inode.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/ramfs/inode.c 2003-01-14 17:18:14.000000000 +0100 @@ -189,19 +189,19 @@ { struct list_head *list; - spin_lock(&dcache_lock); + lock_dcache(); list = dentry->d_subdirs.next; while (list != &dentry->d_subdirs) { struct dentry *de = list_entry(list, struct dentry, d_child); if (ramfs_positive(de)) { - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; } list = list->next; } - spin_unlock(&dcache_lock); + unlock_dcache(); return 1; } diff -durN -X dontdiff linux/fs/readdir.c linux-2.4.20-preempt-mutex-pi2/fs/readdir.c --- linux/fs/readdir.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/readdir.c 2003-01-14 17:18:14.000000000 +0100 @@ -68,7 +68,7 @@ struct dentry *cursor = file->private_data; loff_t n = file->f_pos - 2; - spin_lock(&dcache_lock); + lock_dcache(); p = file->f_dentry->d_subdirs.next; while (n && p != &file->f_dentry->d_subdirs) { struct dentry *next; @@ -79,7 +79,7 @@ } list_del(&cursor->d_child); list_add_tail(&cursor->d_child, p); - spin_unlock(&dcache_lock); + unlock_dcache(); } } up(&file->f_dentry->d_inode->i_sem); @@ -114,16 +114,16 @@ i++; /* fallthrough */ case 1: - spin_lock(&dcache_lock); + lock_dcache(); ino = dentry->d_parent->d_inode->i_ino; - spin_unlock(&dcache_lock); + unlock_dcache(); if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) break; filp->f_pos++; i++; /* fallthrough */ default: - spin_lock(&dcache_lock); + lock_dcache(); if (filp->f_pos == 2) { list_del(q); list_add(q, &dentry->d_subdirs); @@ -134,17 +134,17 @@ if (list_empty(&next->d_hash) || !next->d_inode) continue; - spin_unlock(&dcache_lock); + unlock_dcache(); if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, DT_UNKNOWN) < 0) return 0; - spin_lock(&dcache_lock); + lock_dcache(); /* next is still alive */ list_del(q); list_add(q, p); p = q; filp->f_pos++; } - spin_unlock(&dcache_lock); + unlock_dcache(); } return 0; } diff -durN -X dontdiff linux/fs/reiserfs/inode.c linux-2.4.20-preempt-mutex-pi2/fs/reiserfs/inode.c --- linux/fs/reiserfs/inode.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/reiserfs/inode.c 2003-01-14 17:18:14.000000000 +0100 @@ -1284,18 +1284,18 @@ /* now to find a dentry. * If possible, get a well-connected one */ - spin_lock(&dcache_lock); + lock_dcache(); for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { result = list_entry(lp,struct dentry, d_alias); if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { dget_locked(result); result->d_vfs_flags |= DCACHE_REFERENCED; - spin_unlock(&dcache_lock); + unlock_dcache(); iput(inode); return result; } } - spin_unlock(&dcache_lock); + unlock_dcache(); result = d_alloc_root(inode); if (result == NULL) { iput(inode); diff -durN -X dontdiff linux/fs/smbfs/cache.c linux-2.4.20-preempt-mutex-pi2/fs/smbfs/cache.c --- linux/fs/smbfs/cache.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/smbfs/cache.c 2003-01-14 17:18:14.000000000 +0100 @@ -62,7 +62,7 @@ struct list_head *next; struct dentry *dentry; - spin_lock(&dcache_lock); + lock_dcache(); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { dentry = list_entry(next, struct dentry, d_child); @@ -70,7 +70,7 @@ smb_age_dentry(server, dentry); next = next->next; } - spin_unlock(&dcache_lock); + unlock_dcache(); } /* @@ -96,7 +96,7 @@ } /* If a pointer is invalid, we search the dentry. */ - spin_lock(&dcache_lock); + lock_dcache(); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { dent = list_entry(next, struct dentry, d_child); @@ -111,7 +111,7 @@ } dent = NULL; out_unlock: - spin_unlock(&dcache_lock); + unlock_dcache(); return dent; } diff -durN -X dontdiff linux/fs/umsdos/dir.c linux-2.4.20-preempt-mutex-pi2/fs/umsdos/dir.c --- linux/fs/umsdos/dir.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/umsdos/dir.c 2003-01-14 17:18:14.000000000 +0100 @@ -650,9 +650,9 @@ read_lock(¤t->fs->lock); old_root = dget(current->fs->root); read_unlock(¤t->fs->lock); - spin_lock(&dcache_lock); + lock_dcache(); path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */ - spin_unlock(&dcache_lock); + unlock_dcache(); if (*path == '/') path++; /* skip leading '/' */ diff -durN -X dontdiff linux/fs/vfat/namei.c linux-2.4.20-preempt-mutex-pi2/fs/vfat/namei.c --- linux/fs/vfat/namei.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/fs/vfat/namei.c 2003-01-14 17:18:14.000000000 +0100 @@ -75,12 +75,12 @@ static int vfat_revalidate(struct dentry *dentry, int flags) { PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name)); - spin_lock(&dcache_lock); + lock_dcache(); if (dentry->d_time == dentry->d_parent->d_inode->i_version) { - spin_unlock(&dcache_lock); + unlock_dcache(); return 1; } - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; } diff -durN -X dontdiff linux/include/linux/dcache.h linux-2.4.20-preempt-mutex-pi2/include/linux/dcache.h --- linux/include/linux/dcache.h 2003-01-10 02:53:39.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/include/linux/dcache.h 2003-01-23 01:47:30.000000000 +0100 @@ -6,6 +6,7 @@ #include #include #include +#include /* * linux/include/linux/dcache.h @@ -125,7 +126,18 @@ */ #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ -extern spinlock_t dcache_lock; +#ifdef CONFIG_DCACHE_MTX +extern p_mutex_t dcache_mtx; +#define lock_dcache() p_mutex_down(&dcache_mtx) +#define unlock_dcache() p_mutex_up(&dcache_mtx) +#define atomic_dec_and_lock_dcache(x) atomic_dec_and_mutex_lock(x, &dcache_mtx) +#else +extern spinlock_t dcache_mtx; +#define lock_dcache() spin_lock(&dcache_mtx) +#define unlock_dcache() spin_unlock(&dcache_mtx) +#define atomic_dec_and_lock_dcache(x) atomic_dec_and_lock(x, &dcache_mtx) +#endif + static __inline__ int dname_external(struct dentry *d) { @@ -275,10 +287,10 @@ static __inline__ void d_drop(struct dentry * dentry) { - spin_lock(&dcache_lock); + lock_dcache(); list_del(&dentry->d_hash); INIT_LIST_HEAD(&dentry->d_hash); - spin_unlock(&dcache_lock); + unlock_dcache(); } #endif #endif diff -durN -X dontdiff linux/include/linux/dnotify.h linux-2.4.20-preempt-mutex-pi2/include/linux/dnotify.h --- linux/include/linux/dnotify.h 2003-01-10 02:36:19.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/include/linux/dnotify.h 2003-01-14 17:18:14.000000000 +0100 @@ -30,13 +30,13 @@ static inline void dnotify_parent(struct dentry *dentry, unsigned long event) { struct dentry *parent; - spin_lock(&dcache_lock); + lock_dcache(); parent = dentry->d_parent; if (parent->d_inode->i_dnotify_mask & event) { dget(parent); - spin_unlock(&dcache_lock); + unlock_dcache(); __inode_dir_notify(parent->d_inode, event); dput(parent); } else - spin_unlock(&dcache_lock); + unlock_dcache(); } diff -durN -X dontdiff linux/include/linux/namespace.h linux-2.4.20-preempt-mutex-pi2/include/linux/namespace.h --- linux/include/linux/namespace.h 2003-01-10 02:36:19.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/include/linux/namespace.h 2003-01-14 17:18:14.000000000 +0100 @@ -15,9 +15,9 @@ { if (atomic_dec_and_test(&namespace->count)) { down_write(&namespace->sem); - spin_lock(&dcache_lock); + lock_dcache(); umount_tree(namespace->root); - spin_unlock(&dcache_lock); + unlock_dcache(); up_write(&namespace->sem); kfree(namespace); } diff -durN -X dontdiff linux/include/linux/pmutex.h linux-2.4.20-preempt-mutex-pi2/include/linux/pmutex.h --- linux/include/linux/pmutex.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/include/linux/pmutex.h 2003-02-01 00:38:08.000000000 +0100 @@ -0,0 +1,156 @@ +/* + * pmutex.h -- mutex implementation with priority inheritance + * + * See + * http://inf33-www.informatik.unibw-muenchen.de/research/linux/mutex.html + * for details of the used priority inheritance protocol. + * + * Copyright (C) 2002 Dirk Grambow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#ifndef __LINUX_PMUTEX_H +#define __LINUX_PMUTEX_H + +#include +#include +#include + +struct p_sleeper_list { + struct list_head list; + struct task_struct *task; +}; + +typedef struct p_sleeper_list p_sleeper_list_t; + +struct p_mutex { + int m_lock, m_missed; + struct list_head m_sleepers; +#ifdef CONFIG_MTX_PI + struct task_struct *owner; +#endif +}; + +typedef struct p_mutex p_mutex_t; + +#ifdef CONFIG_MTX_PI +#define PM_INVALID 100 + +struct mtx_set { + struct list_head list; + p_mutex_t *mtx; + unsigned long inherited_prio; +}; + +typedef struct mtx_set mtx_set_t; +#endif + +extern int atomic_dec_and_mutex_lock(atomic_t *atomic, p_mutex_t *mtx); + +#ifdef CONFIG_MTX_PI + +#define DECLARE_P_MUTEX(x) \ +p_mutex_t (x) = { 1, 0, LIST_HEAD_INIT((x).m_sleepers), 0} + +#else + +#define DECLARE_P_MUTEX(x) \ +p_mutex_t (x) = { 1, 0, LIST_HEAD_INIT((x).m_sleepers)} + +#endif + + +static inline void p_mutex_init(p_mutex_t *mtx) +{ + mtx->m_lock = 1; + mtx->m_missed = 0; + INIT_LIST_HEAD(&mtx->m_sleepers); +#ifdef CONFIG_MTX_PI + mtx->owner = 0; +#endif +} + +extern void __p_mutex_down(p_mutex_t *mtx); +extern void __p_mutex_up(p_mutex_t *mtx); + +/* + * The following i386 p_mutex_down() and p_mutex_up() implementations are + * based on their include/asm/semaphore.h counterparts. + */ + +static inline void p_mutex_down(p_mutex_t *mtx) +{ + __asm__ __volatile__ ( + "\t" +#ifdef CONFIG_MTX_PI + "pushfl\n\t" + "cli\n\t" +#endif + LOCK "decl %0\n\t" + "js 2f\n" +#ifdef CONFIG_MTX_PI + "\tmovl %%esp, %1\n\t" + "andl $-8192, %1\n\t" + "popfl\n" +#endif + "1:\n" + ".subsection 1\n" + "2:\t" +#ifdef CONFIG_MTX_PI + "popfl\n\t" +#endif + "pushl %%eax\n\t" + "pushl %%edx\n\t" + "pushl %%ecx\n\t" + "call __p_mutex_down\n\t" + "popl %%ecx\n\t" + "popl %%edx\n\t" + "popl %%eax\n\t" + "jmp 1b\n" + ".subsection 0\n" + :"=m" (mtx->m_lock) +#ifdef CONFIG_MTX_PI + , "=m" (mtx->owner) +#endif + :"c" (mtx) + :"memory"); +} + + +static inline void p_mutex_up(p_mutex_t *mtx) +{ + __asm__ __volatile__ ( + "\t" + LOCK "incl %0\n\t" + "jle 2f\n" + "1:\n" + ".subsection 1\n" + "2:\tpushl %%eax\n\t" + "pushl %%edx\n\t" + "pushl %%ecx\n\t" + "call __p_mutex_up\n\t" + "popl %%ecx\n\t" + "popl %%edx\n\t" + "popl %%eax\n\t" + "jmp 1b\n" + ".subsection 0\n" + :"=m" (mtx->m_lock) + :"c" (mtx) + :"memory"); +} +#endif diff -durN -X dontdiff linux/include/linux/sched.h linux-2.4.20-preempt-mutex-pi2/include/linux/sched.h --- linux/include/linux/sched.h 2003-01-10 02:53:39.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/include/linux/sched.h 2003-01-23 01:47:30.000000000 +0100 @@ -26,6 +26,7 @@ #include #include #include +#include struct exec_domain; @@ -337,6 +338,12 @@ unsigned int allocation_order, nr_local_pages; unsigned long flags; +#ifdef CONFIG_MTX_PI + struct list_head mtx_set; + p_mutex_t *waiting_mtx; + unsigned long saved_prio; +#endif + /* task state */ struct linux_binfmt *binfmt; int exit_code, exit_signal; @@ -940,9 +947,9 @@ rootmnt = mntget(current->fs->rootmnt); root = dget(current->fs->root); read_unlock(¤t->fs->lock); - spin_lock(&dcache_lock); + lock_dcache(); res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); - spin_unlock(&dcache_lock); + unlock_dcache(); dput(root); mntput(rootmnt); return res; diff -durN -X dontdiff linux/kernel/Makefile linux-2.4.20-preempt-mutex-pi2/kernel/Makefile --- linux/kernel/Makefile 2003-01-10 02:36:16.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/kernel/Makefile 2003-01-14 17:18:14.000000000 +0100 @@ -19,6 +19,7 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PREEMPT) += pmutex.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -durN -X dontdiff linux/kernel/fork.c linux-2.4.20-preempt-mutex-pi2/kernel/fork.c --- linux/kernel/fork.c 2003-01-10 02:49:27.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/kernel/fork.c 2003-01-14 17:18:14.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -636,6 +637,13 @@ */ p->preempt_count = 1; #endif + +#ifdef CONFIG_MTX_PI + INIT_LIST_HEAD(&p->mtx_set); + p->waiting_mtx = 0; + p->saved_prio = PM_INVALID; +#endif + p->did_exec = 0; p->swappable = 0; p->state = TASK_UNINTERRUPTIBLE; diff -durN -X dontdiff linux/kernel/ksyms.c linux-2.4.20-preempt-mutex-pi2/kernel/ksyms.c --- linux/kernel/ksyms.c 2003-01-10 02:49:27.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/kernel/ksyms.c 2003-01-14 17:26:06.000000000 +0100 @@ -48,6 +48,7 @@ #include #include #include +#include #include #if defined(CONFIG_PROC_FS) @@ -153,7 +154,9 @@ EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(lookup_hash); EXPORT_SYMBOL(sys_close); -EXPORT_SYMBOL(dcache_lock); +EXPORT_SYMBOL(dcache_mtx); +EXPORT_SYMBOL_NOVERS(__p_mutex_down); /* These functions are called from inline-assembler instructions */ +EXPORT_SYMBOL_NOVERS(__p_mutex_up); /* Since these instructions are in quotation marks, modversions must be bypassed */ EXPORT_SYMBOL(d_alloc_root); EXPORT_SYMBOL(d_delete); EXPORT_SYMBOL(dget_locked); diff -durN -X dontdiff linux/kernel/pmutex.c linux-2.4.20-preempt-mutex-pi2/kernel/pmutex.c --- linux/kernel/pmutex.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/kernel/pmutex.c 2003-01-14 17:18:14.000000000 +0100 @@ -0,0 +1,178 @@ +/* + * pmutex.c -- mutex implementation with priority inheritance + * + * See + * http://inf33-www.informatik.unibw-muenchen.de/research/linux/mutex.html + * for details of the used priority inheritance protocol. + * + * Copyright (C) 2002 Dirk Grambow + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include +#include +#include +#include + +static spinlock_t m_spin_lock = SPIN_LOCK_UNLOCKED; + +#ifdef CONFIG_MTX_PI +#define initial_prio(task) \ + (task->saved_prio == PM_INVALID ? task->rt_priority : task->saved_prio) + +static inline void inherit(p_mutex_t *mtx, unsigned long prio) +{ + struct list_head *pos; + struct task_struct *owner; + mtx_set_t *entry; + + do { + owner = mtx->owner; + + list_for_each(pos, &owner->mtx_set) { + entry = list_entry(pos, mtx_set_t, list); + if (entry->mtx == mtx) { + if (entry->inherited_prio < prio) { + entry->inherited_prio = prio; + goto set_prio; + } + return; + } + } + + entry = kmalloc(sizeof(mtx_set_t), GFP_KERNEL); + entry->mtx = mtx; + entry->inherited_prio = prio; + list_add(&entry->list, pos); + + if (owner->saved_prio == PM_INVALID) + owner->saved_prio = owner->rt_priority; + if (owner->rt_priority == 0) + owner->policy = SCHED_FIFO; + + set_prio: + if (owner->rt_priority < prio) + owner->rt_priority = prio; + + mtx = owner->waiting_mtx; + } while (mtx != 0 && prio > initial_prio(mtx->owner)); +} + +static inline int remove_inherited_prio(struct task_struct *t, p_mutex_t *mtx) +{ + struct list_head *pos; + mtx_set_t *entry; + + list_for_each(pos, &t->mtx_set) { + entry = list_entry(pos, mtx_set_t, list); + if (entry->mtx == mtx) + break; + } + if (pos != &t->mtx_set) { + list_del(pos); + kfree(entry); + return 1; + } + return 0; +} +#endif + +void __p_mutex_down(p_mutex_t *mtx) +{ + p_sleeper_list_t new; + + new.task = current; + + spin_lock(&m_spin_lock); + + if (mtx->m_missed) { + mtx->m_missed = 0; + +#ifdef CONFIG_MTX_PI + mtx->owner = current; +#endif + + spin_unlock(&m_spin_lock); + return; + } + + list_add(&new.list, &mtx->m_sleepers); + +#ifdef CONFIG_MTX_PI + if (current->rt_priority > initial_prio(mtx->owner)) + inherit(mtx, current->rt_priority); + + current->waiting_mtx = mtx; +#endif + + current->state = TASK_UNINTERRUPTIBLE; + + spin_unlock(&m_spin_lock); + + schedule(); +} + +void __p_mutex_up(p_mutex_t *mtx) +{ + struct list_head *pos, *next; + unsigned long act, highest; + + spin_lock(&m_spin_lock); + + if (list_empty(&mtx->m_sleepers)) { + mtx->m_missed = 1; + spin_unlock(&m_spin_lock); + return; + } + + next = mtx->m_sleepers.next; + highest = 0; + list_for_each(pos, &mtx->m_sleepers) { + act = list_entry(pos, p_sleeper_list_t, list)->task->rt_priority; + if (act > highest) { + highest = act; + next = pos; + } + } + +#ifdef CONFIG_MTX_PI + if (remove_inherited_prio(current, mtx)) { + if (list_empty(¤t->mtx_set)) { + current->rt_priority = current->saved_prio; + if (current->saved_prio == 0) + current->policy = SCHED_OTHER; + current->saved_prio = PM_INVALID; + } else { + highest = 0; + list_for_each(pos, ¤t->mtx_set) { + act = list_entry(pos, mtx_set_t, list)->inherited_prio; + if (act > highest) + highest = act; + } + current->rt_priority = highest; + } + } + mtx->owner = list_entry(next, p_sleeper_list_t, list)->task; + mtx->owner->waiting_mtx = 0; +#endif + + list_del(next); + wake_up_process(list_entry(next, p_sleeper_list_t, list)->task); + + spin_unlock(&m_spin_lock); +} diff -durN -X dontdiff linux/mm/shmem.c linux-2.4.20-preempt-mutex-pi2/mm/shmem.c --- linux/mm/shmem.c 2003-01-10 02:36:08.000000000 +0100 +++ linux-2.4.20-preempt-mutex-pi2/mm/shmem.c 2003-01-14 17:18:14.000000000 +0100 @@ -1088,19 +1088,19 @@ { struct list_head *list; - spin_lock(&dcache_lock); + lock_dcache(); list = dentry->d_subdirs.next; while (list != &dentry->d_subdirs) { struct dentry *de = list_entry(list, struct dentry, d_child); if (shmem_positive(de)) { - spin_unlock(&dcache_lock); + unlock_dcache(); return 0; } list = list->next; } - spin_unlock(&dcache_lock); + unlock_dcache(); return 1; }