[SSI] openssi/kernel/ipc msg.c, 1.16, 1.17 sem.c, 1.32, 1.33 shm.c, 1.27, 1.28 util.c, 1.10, 1.11 util.h, 1.12, 1.13
Roger Tsang <[email protected]> Fri, 05 Mar 2010 06:30:23 +0000
| Newsgroups | gmane.linux.cluster.ssic.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/ssic-linux/openssi/kernel/ipc
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv9483/kernel/ipc
Modified Files:
Tag: OPENSSI-FC
msg.c sem.c shm.c util.c util.h
Log Message:
IPC:
- Fix partially initialized shmid_kernel_svr.shm_perm structure.
- Fix ipc/sem.c:exit_sem() GCC warning: ISO C90 forbids mixed declarations and
code.
- Split ssi_shm_setup() into separate functions ssi_shm_setup_client/new() to
reduce stack usage in some paths.
IPC (#ifdef IPC_SHM_RACE_FIX):
- Fix shm_svr_rmid() called without spinlock for the ID.
- Fix race deferencing invalid struct shmid_kernel, shmid_kernel_svr.
- Enable lockfree shmid_kernel_svr IPC id lookup. Use ipc_rcu_alloc and IPC
reference counting.
- Reduce contention. Avoid the ipc_ids mutex. Use per IPC id spinlock.
- Fix cli_ipcname_findid() race with cli_ipcname_getid() could overwrite
existing IPC segment.
- Fix non-critical section under shm_ids.sem lock in shm_create_cli_entry().
- Prevent re-acquire shm_ids.sem in shm_destroy() path. ripc_shm_rmid() no
longer returns with shm_ids.sem unlocked.
- Remove contention in shmem_svr_lookup(); no longer acquire shm_ids_svr.sem.
- Fix do_shmat() possible hang calling dput() while holding spinlock.
- Fix cfs_shm_node_mnts[] race.
- Fix inode leak in ssi_shm_setup() error path when do_shm_register() fails.
IPC (#ifdef IPC_SHM_LOCK_DEST_FIX):
- Fix [ ssic-linux-Bug 2838006 ] Corrupt SHM_LOCK_DEST flag.
- Refactor ipc_shm_nodedown() for SHM_LOCK_DEST flag. Use SHM_LOCK_DEST flag.
- Fix ripc_drop_locks() error path dereferencing NULL pointer in
ipc_drop_locks().
IPC (#ifdef CFS_IPCSHM_DENTRY):
- ssi_shm_setup_client() use d_instantiate_unique() to prevent duplicate
entries.
cluster/ssi/cfs/cfs_ipcshm.c | 422 ++++++++++++++++++-----------
cluster/ssi/cfs/cfsproc.c | 6
cluster/ssi/ipc/ipcshm_svr.c | 280 +++++++++++--------
cluster/ssi/ipc/namesvr_func.c | 12
cluster/ssi/vproc/reopen.c | 30 +-
include/cluster/ssi/cfs/cfs_fs.h | 16 +
include/cluster/ssi/ipc/shm.h | 13
include/linux/shm.h | 7
ipc/msg.c | 6
ipc/sem.c | 17 -
ipc/shm.c | 450 ++++++++++++++++++++-----------
ipc/util.c | 18 -
ipc/util.h | 5
mm/shmem.c | 9
14 files changed, 845 insertions(+), 446 deletions(-)
Index: util.h
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/util.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- util.h 17 Jan 2010 11:57:05 -0000 1.12
+++ util.h 5 Mar 2010 06:30:21 -0000 1.13
@@ -34,11 +34,6 @@
int max_id;
unsigned short seq;
unsigned short seq_max;
-#ifdef CONFIG_SSI
-#ifdef IPC_SHM_RACE_FIX
- int lock_dest_id; /* id of entry locked for destroy aka. SHM_LOCK_DEST */
-#endif
-#endif
struct semaphore sem;
struct ipc_id_ary nullentry;
struct ipc_id_ary* entries;
Index: sem.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/sem.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- sem.c 2 Feb 2010 05:19:30 -0000 1.32
+++ sem.c 5 Mar 2010 06:30:21 -0000 1.33
@@ -321,10 +321,16 @@
return retval;
}
}
+#ifdef IPC_SHM_RACE_FIX
+ SSI_ASSERT(server == this_node);
+#else
up(&sem_ids.sem);
+#endif
retval = cli_ipcname_getid(NAME_SERVICE_SEM, key, semflg, &newid,
&server, ssi_get_localview(), &create);
+#ifndef IPC_SHM_RACE_FIX
down(&sem_ids.sem);
+#endif
if (!retval) {
retval = newid;
if (!create)
@@ -1980,6 +1986,12 @@
{
struct sem_undo_list *undo_list;
struct sem_undo *u, **up;
+#ifdef CONFIG_SSI
+ ssi_procstate_t pstate;
+ key_t key;
+ clusternode_t svr_node=0;
+ int rval, flags, view, sz;
+#endif
undo_list = tsk->sysvsem.undo_list;
if (!undo_list)
@@ -1989,11 +2001,6 @@
return;
#ifdef CONFIG_SSI
- int rval, flags, view, sz;
- clusternode_t svr_node=0;
- ssi_procstate_t pstate;
- key_t key;
-
/* There's no need to hold the semundo list lock, as current
* is the last task exiting for this undo list.
*/
Index: shm.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/shm.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- shm.c 2 Feb 2010 05:19:30 -0000 1.27
+++ shm.c 5 Mar 2010 06:30:21 -0000 1.28
@@ -72,6 +72,36 @@
#define PRINT_HEADER \
len += sprintf(buffer, " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime view node_num\n");
+#ifdef IPC_SHM_RACE_FIX
+struct shmid_kernel *shm_cli_get(int id)
+{
+ return shm_get(id);
+}
+struct shmid_kernel_svr *shm_svr_get(int id)
+{
+ return (struct shmid_kernel_svr *) ipc_get(&shm_ids_svr, id);
+}
+struct shmid_kernel *shm_cli_lock(int id)
+{
+ return shm_lock(id);
+}
+void shm_cli_unlock(struct shmid_kernel *shp)
+{
+ shm_unlock(shp);
+}
+struct shmid_kernel_svr *shm_svr_lock(int id)
+{
+ return (struct shmid_kernel_svr *) ipc_lock(&shm_ids_svr, id);
+}
+void shm_svr_unlock(struct shmid_kernel_svr *svp)
+{
+ ipc_unlock(&(svp)->shm_perm);
+}
+int shm_sem_owned(void)
+{
+ return sem_owned(&shm_ids.sem);
+}
+#else /* IPC_SHM_RACE_FIX */
inline struct shmid_kernel_svr *shm_svr_get(int id)
{
return ((struct shmid_kernel_svr *)ipc_get(&shm_ids_svr,id));
@@ -81,9 +111,11 @@
{
return ((struct shmid_kernel *)ipc_get(&shm_ids,id));
}
+#endif /* !IPC_SHM_RACE_FIX */
+
static int newseg (key_t, int, size_t, struct file *, int, int);
-#else
+#else /* CONFIG_SSI */
#define SHM_MAX_ID shm_ids.max_id
#define SHM_IPC_ID(i,seq) shm_buildid(i,seq)
@@ -132,7 +164,7 @@
inline struct shmid_kernel *shm_rmid(int id)
#else
static inline struct shmid_kernel *shm_rmid(int id)
-#endif /* CONFIG_SSI */
+#endif /* !CONFIG_SSI */
{
return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
}
@@ -143,7 +175,7 @@
return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni, shp->id);
#else
return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
-#endif /* CONFIG_SSI */
+#endif /* !CONFIG_SSI */
}
@@ -283,6 +315,7 @@
};
#ifdef CONFIG_SSI
+/* Must be called with shm_ids.sem locked */
static int newseg (key_t key, int shmflg, size_t size, struct file *fp,
int view, int newid)
#else
@@ -587,11 +620,20 @@
if ((cmd^IPC_64) == IPC_RMID) {
/* if its local & svr is down, then remove it */
+#ifdef IPC_SHM_RACE_FIX
+ shp = shm_cli_lock(shmid);
+ if (!shp)
+ return -EINVAL;
+ if (shp->shm_node != this_node)
+ svrnode = 0;
+ shm_cli_unlock(shp);
+#else
shp = shm_cli_get(shmid);
if (!shp)
return -EINVAL;
if (shp->shm_node != this_node)
svrnode = 0;
+#endif
}
else
return -EINVAL;
@@ -1014,7 +1056,7 @@
err = -EINVAL;
goto out;
}
-#endif /* CONFIG_SSI */
+#endif /* !CONFIG_SSI */
err = shm_checkid(shp,shmid);
if (err) {
#ifdef CONFIG_SSI
@@ -1045,44 +1087,79 @@
/* Setup for remote access */
if (shp->shm_file->f_op != &cfs_shm_file_operations) {
struct dentry *de;
+#ifndef IPC_SHM_RACE_FIX
struct vfsmount *new_mnt=NULL;
+#else
+ struct dentry *old_dentry = NULL;
+ struct vfsmount *old_mnt = NULL;
+ ipc_rcu_getref(shp);
+#endif /* IPC_SHM_RACE_FIX */
shm_unlock(shp);
- de = ssi_shm_setup(shp->shm_node, shp->id, 0,
+ de = ssi_shm_setup(shp->shm_node, shp->id, 0,
shp->shm_perm.key);
down (&shm_ids.sem);
+#ifdef IPC_SHM_RACE_FIX
+ ipc_lock_by_ptr(&shp->shm_perm);
+ ipc_rcu_putref(shp);
+ if (!shm_get(shmid)) {
+ shm_unlock(shp);
+ up (&shm_ids.sem);
+ dput(de);
+ return -EINVAL;
+ }
+#else
shp = shm_lock(shmid);
if (!shp) {
dput(de);
up (&shm_ids.sem);
return -EINVAL;
}
+#endif /* !IPC_SHM_RACE_FIX */
if (shp->shm_file->f_op == &cfs_shm_file_operations) {
+#ifdef IPC_SHM_RACE_FIX
+ old_dentry = de;
+#else
dput(de);
+#endif
goto cont;
}
if (de) {
/* switch file to cfs and cleanup */
+#ifdef IPC_SHM_RACE_FIX
+ old_dentry = shp->shm_file->f_dentry;
+ shp->shm_file->f_dentry = de;
+
+ old_mnt = shp->shm_file->f_vfsmnt;
+ shp->shm_file->f_vfsmnt = mntget(
+ cfs_shm_node_mnts[shp->shm_node]);
+#else
dput(shp->shm_file->f_dentry);
mntput(shp->shm_file->f_vfsmnt);
new_mnt = (struct vfsmount *)
cfs_shm_node_mnts[shp->shm_node];
shp->shm_file->f_dentry = de;
shp->shm_file->f_vfsmnt = mntget(new_mnt);
+#endif
shp->shm_file->f_op = &cfs_shm_file_operations;
shp->shm_file->f_mapping =
de->d_inode->i_mapping;
}
else {
- shp->shm_node = 0;
- shm_destroy(shp);
+ ssi_local_destroy(shp);
up(&shm_ids.sem);
return -EINVAL;
}
cont:
up(&shm_ids.sem);
+#ifdef IPC_SHM_RACE_FIX
+ if (old_dentry)
+ dput(old_dentry);
+ if (old_mnt)
+ mntput(old_mnt);
+#endif
}
#endif /* CONFIG_SSI */
file = shp->shm_file;
@@ -1130,13 +1207,12 @@
ssi_err:
if (shp->shm_node != this_node &&
shp->shm_file->f_op != &cfs_shm_file_operations) {
- shp->shm_node = 0;
shm_unlock(shp);
down (&shm_ids.sem);
if(!(shp = shm_lock(shmid)))
BUG();
- shm_destroy(shp);
- up (&shm_ids.sem);
+ ssi_local_destroy(shp);
+ up(&shm_ids.sem);
}
else
shm_unlock(shp);
@@ -1190,10 +1266,11 @@
*/
#ifdef CONFIG_SSI
if ((vma->vm_ops==&cfs_shm_vm_ops || is_vm_hugetlb_page(vma)) &&
+ (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
#else
if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
-#endif /* CONFIG_SSI */
(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
+#endif /* CONFIG_SSI */
size = vma->vm_file->f_dentry->d_inode->i_size;
@@ -1222,10 +1299,11 @@
/* finding a matching vma now does not alter retval */
#ifdef CONFIG_SSI
if ((vma->vm_ops==&cfs_shm_vm_ops || is_vm_hugetlb_page(vma)) &&
+ (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
#else
if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
-#endif /* CONFIG_SSI */
(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
+#endif /* CONFIG_SSI */
do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
vma = next;
@@ -1238,11 +1316,9 @@
#ifdef CONFIG_SSI
struct shmid_kernel_svr *shm_svr_rmid(int id)
{
- struct shmid_kernel_svr *svr;
-
- svr = (struct shmid_kernel_svr *)ipc_rmid(&shm_ids_svr,id);
- return svr;
+ return (struct shmid_kernel_svr *)ipc_rmid(&shm_ids_svr,id);
}
+
int shm_svr_addid(struct shmid_kernel_svr *shm_svr)
{
struct ipc_ids *ids = &shm_ids_svr;
@@ -1250,6 +1326,9 @@
struct kern_ipc_perm *new = &(shm_svr->shm_perm);
int size;
+ spin_lock_init(&new->lock);
+ new->deleted = 0;
+
down(&shm_ids_svr.sem);
size = ipc_grow_ary(ids,shmsvrsz+1);
ids->in_use++;
@@ -1267,14 +1346,24 @@
clusternode_t
shm_get_svrnode(struct dentry *de)
{
- int id = de->d_inode->i_ino;
struct shmid_kernel *shp;
+#ifdef IPC_SHM_RACE_FIX
+ clusternode_t node;
+ shp = shm_lock(de->d_inode->i_ino);
+ if (!shp)
+ return CLUSTERNODE_INVAL;
+ node = shp->shm_node;
+ shm_unlock(shp);
+ return node;
+#else /* IPC_SHM_RACE_FIX */
+ int id = de->d_inode->i_ino;
shp = shm_get(id);
if (shp)
return shp->shm_node;
else
return CLUSTERNODE_INVAL;
+#endif /* !IPC_SHM_RACE_FIX */
}
/**
@@ -1284,24 +1373,25 @@
int
shm_create_cli_entry(struct file **filepp)
{
- struct file *file = *filepp;
- struct file *old_file = NULL;
- int shmid = file->f_dentry->d_inode->i_ino;
+ struct file *old_file, *file = *filepp;
struct shmid_kernel *shp;
clusternode_t svrnode;
key_t key;
long id;
- int flags;
- int view=0;
- int sz;
+ int shmid = file->f_dentry->d_inode->i_ino;
+ int flags, sz, view=0;
BUG_ON(strncmp(file->f_dentry->d_name.name, "SYSV", 4));
/* create client */
+#ifndef IPC_SHM_RACE_FIX
down(&shm_ids.sem);
+#endif
shp = shm_lock(shmid);
if (!shp) {
+#ifndef IPC_SHM_RACE_FIX
up(&shm_ids.sem);
+#endif
if (cli_ipcname_findid(NAME_SERVICE_SHM, shmid,
&key,
&svrnode,
@@ -1312,8 +1402,12 @@
down(&shm_ids.sem);
shp = shm_lock(shmid);
- if (shp)
+ if (shp) {
+#ifdef IPC_SHM_RACE_FIX
+ up(&shm_ids.sem);
+#endif
goto found;
+ }
id = newseg(key, flags, sz, file, view, shmid);
if (id < 0) {
up(&shm_ids.sem);
@@ -1321,25 +1415,33 @@
}
shp = shm_lock(shmid);
shp->shm_node = svrnode;
+#ifdef IPC_SHM_RACE_FIX
+ up(&shm_ids.sem);
+#endif
}
found:
if (shmid != shp->id) {
- printk("Failed to create new cli entry, failing migrate\n");
shm_unlock(shp);
+#ifndef IPC_SHM_RACE_FIX
up(&shm_ids.sem);
+#endif
+ printk(KERN_WARNING "%s: Failed to create new cli entry, "
+ "failing migrate\n", __FUNCTION__);
return -EINVAL;
}
- else {
- if (shp->shm_file != file) {
- old_file = file;
- *filepp = file = shp->shm_file;
- }
- }
+
+ if (shp->shm_file != file) {
+ old_file = file;
+ *filepp = file = shp->shm_file;
+ } else
+ old_file = NULL;
get_file(file);
shp->shm_file->f_op = &cfs_shm_file_operations;
shp->shm_file->f_mode |= (FMODE_WRITE|FMODE_READ);
shm_unlock(shp);
+#ifndef IPC_SHM_RACE_FIX
up(&shm_ids.sem);
+#endif
if (old_file)
fput(old_file);
return 0;
@@ -1348,10 +1450,46 @@
int
ipcname_failover_create(key_t key, int shmid, int size, clusternode_t svrnode, int view)
{
- int id;
struct shmid_kernel *shp;
+ int id;
/* see if client already exists */
+#ifdef IPC_SHM_RACE_FIX
+ shp = shm_lock(shmid);
+ if (shp)
+ goto found;
+
+ down(&shm_ids.sem);
+ shp = shm_lock(shmid);
+ if (shp) {
+ up(&shm_ids.sem);
+ goto found;
+ }
+
+ /* create client */
+ id = newseg(key, 0, size, NULL, view, shmid);
+ if (id < 0) {
+ up(&shm_ids.sem);
+ printk(KERN_WARNING "%s: Unable create new segment %d\n",
+ __FUNCTION__, shmid);
+ return -EINVAL;
+ }
+ shp = shm_lock(shmid);
+ shp->shm_node = svrnode;
+ shm_unlock(shp);
+ up(&shm_ids.sem);
+ return 0;
+found:
+ if (shp->id != shmid || shp->shm_perm.key != key ||
+ shp->shm_node != svrnode) {
+ shm_unlock(shp);
+ printk(KERN_WARNING "%s: Different shp already "
+ "exists %d %d\n", __FUNCTION__, shp->id, shmid);
+ return -EINVAL;
+ }
+ shm_unlock(shp);
+ return 0;
+#else /* IPC_SHM_RACE_FIX */
down(&shm_ids.sem);
shp = shm_cli_get(shmid);
if (shp) {
@@ -1370,136 +1508,110 @@
shm_unlock(shp);
up(&shm_ids.sem);
return 0;
+#endif /* !IPC_SHM_RACE_FIX */
}
void
ipc_shm_nodedown(clusternode_t node)
{
- int id;
- struct shmid_kernel *shp;
-#ifdef IPC_SHM_LOCK_DEST_FIX
- struct ipc_id_ary* entries;
- int max_id, shm_id, shm_ids_sem_held, shm_node_found = 1;
-#else
struct ipc_ids *ids = &shm_ids;
+ struct shmid_kernel *shp;
+ int id;
+#ifdef IPC_SHM_RACE_FIX
+ struct vfsmount *mnt;
+ int sem_held;
+ int last_id, max_id;
+ char retry, use_bitmap, shm_lock_dest;
+ DECLARE_BITMAP(retry_bitmap, IPCMNI);
+
+ bitmap_zero(retry_bitmap, IPCMNI);
+ retry = use_bitmap = shm_lock_dest = 0;
#endif
icssvr_nodedown_svc_wait(node, cluster_ipc_svc);
-#ifdef IPC_SHM_LOCK_DEST_FIX
-again:
- shm_ids_sem_held = 1;
- if (shm_node_found) {
- /* Cannot call down() since we are not certain if a SHM segment
- * for DOWN node has shm_ids.sem for SHM_LOCK_DEST.
- */
- while (down_trylock(&shm_ids.sem)) {
- if (shm_ids.lock_dest_id != -1) {
- /* SHM_LOCK_DEST for some segment not necessarily
- * the segment for DOWN node.
- */
- shm_ids_sem_held = 0;
- break;
- }
- nidelay(HZ/20);
- }
- /* If none of the SHM segments for DOWN node
- * has SHM_LOCK_DEST we can call down().
- */
- shm_node_found = 0;
- } else
- down(&shm_ids.sem);
-
- max_id = shm_ids_sem_held ? shm_ids.max_id : shm_ctlmni;
- for (id = 0; id <= max_id; id++) {
- if (!shm_ids_sem_held) {
- /* avoid races; based on ipc_lock() */
- rcu_read_lock();
- entries = rcu_dereference(shm_ids.entries);
- shp = (struct shmid_kernel *)entries->p[id];
- if (!shp || shp->shm_perm.deleted) {
- rcu_read_unlock();
- continue;
- }
- if (shp->shm_node != node) {
- rcu_read_unlock();
- continue;
- }
- shm_id = shp->id;
- rcu_read_unlock();
-
- /* barrier for shm_ids.lock_dest_id */
- shm_ids_sem_held = !down_trylock(&shm_ids.sem);
- if (shm_ids_sem_held) {
- if (id != 0)
- id = -1; /* restart for loop */
- max_id = shm_ids.max_id;
- }
-
- shm_node_found = 1;
-
- if (shm_id != shm_ids.lock_dest_id)
- continue;
- /* Now we can obtain shm_ids.sem without possibility of
- * deadlock since this segment has shm_ids.lock_dest_id
- * (SHM_LOCK_DEST). Even if we raced we don't expect
- * another thread for DOWN node to acquire SHM_LOCK_DEST.
- */
- } else {
- /* shm_ids.sem held */
- shp = (struct shmid_kernel *)shm_ids.entries->p[id];
- if (!shp)
- continue;
- if (shp->shm_node == this_node)
- shm_svr_unregister(shp->id, node);
- if (shp->shm_node != node)
- continue;
- shm_id = shp->id;
- }
+#ifdef IPC_SHM_RACE_FIX
+ write_lock(&cfs_shm_node_mnts_lock);
+ mnt = mntget(cfs_shm_node_mnts[node]);
+ cfs_shm_node_mnts[node] = NULL;
+ write_unlock(&cfs_shm_node_mnts_lock);
+ mntput(mnt);
- shp = (struct shmid_kernel *)ipc_get_locks(shm_id, &shm_ids, 0);
+ sem_held = !down_trylock(&ids->sem);
+ max_id = sem_held ? ids->max_id : shm_ctlmni;
- if (!shm_ids_sem_held) {
- shm_ids_sem_held = 1;
- if (!shp || shp->id != shm_ids.lock_dest_id) {
- /* Lost race with ripc_shm_rmid(), etc. */
- if (shp) {
- ipc_drop_locks(shp->id,
- (struct kern_ipc_perm *)shp,
- &shm_ids, 0);
- shp = (struct shmid_kernel *)
- ipc_get_locks(shm_id, &shm_ids, 1);
- } else
- down(&shm_ids.sem);
- max_id = shm_ids.max_id;
- } else {
- /* shm_ids.sem held for SHM_LOCK_DEST */
- max_id = shm_ids.max_id; /* avoided barrier */
- }
- if (id != 0)
- id = -1; /* restart for loop */
+ SSI_ASSERT(max_id < IPCMNI);
+ last_id = max_id;
+again:
+ for (id = 0; id <= max_id; id++) {
+ if (use_bitmap && !test_bit(id, retry_bitmap)) {
+ id = find_next_bit(retry_bitmap, max_id+1, id+1);
+ if (id > max_id)
+ break;
}
- /* shm_ids.sem held */
+ shp = shm_lock(id);
if (!shp)
continue;
-
- shp->shm_flags |= SHM_DEST;
+ if (shp->shm_node == this_node) {
+ SSI_ASSERT(shp->id == id);
+ shm_unlock(shp);
+ shm_svr_unregister(id, node);
+ continue;
+ } else if (shp->shm_node != node) {
+ shm_unlock(shp);
+ continue;
+ }
+ if (!sem_held) {
+ /* SSI_XXX: Could be faster if we tracked the ID */
+ if (shp->shm_flags & SHM_LOCK_DEST) {
+ if (last_id > id)
+ last_id = id;
+ shm_lock_dest = 1;
+ sem_held = 1;
+ } else
+ sem_held = !down_trylock(&ids->sem);
+ }
if (shp->shm_nattch == 0) {
- SSI_ASSERT(shm_ids_sem_held);
-
+ if (!sem_held) {
+ if (!(shp->shm_flags & SHM_DEST))
+ shp->shm_flags |= SHM_DEST;
+ shm_unlock(shp);
+ __set_bit(id, retry_bitmap);
+ if (!retry)
+ retry = 1;
+ continue; /* looking for SHM_LOCK_DEST */
+ }
+ SSI_ASSERT(shp->id == id);
ssi_local_destroy(shp);
- cli_ipcname_rmid(NAME_SERVICE_SHM, shm_id);
- /* ssi_local_destroy() released shp.shm_perm.lock */
- /* shm_ids.sem still held */
- } else
- ipc_drop_locks(shp->id, (struct kern_ipc_perm *)shp,
- &shm_ids, 0);
+ cli_ipcname_rmid(NAME_SERVICE_SHM, id);
+ } else {
+ if (!(shp->shm_flags & SHM_DEST))
+ shp->shm_flags |= SHM_DEST;
+ shm_unlock(shp);
+ }
}
- if (!shm_ids_sem_held)
+ if (retry) {
+ retry = 0;
+ if (shm_lock_dest) {
+ /* SHM_LOCK_DEST flag encountered.
+ * ids->sem was held the whole time
+ * so our retry_bitmap is accurate.
+ */
+ SSI_ASSERT(sem_held);
+ if (last_id == 0)
+ goto out;
+ max_id = last_id - 1;
+ use_bitmap = 1;
+ } else if (!sem_held) {
+ down(&ids->sem);
+ sem_held = 1;
+ }
goto again;
-
- up(&shm_ids.sem);
-#else /* !IPC_SHM_LOCK_DEST_FIX */
+ }
+out:
+ if (sem_held)
+ up(&ids->sem);
+#else /* IPC_SHM_RACE_FIX */
for (id = 0; id <= ids->max_id; id++) {
if(ids->entries->p[id] == NULL)
continue;
@@ -1513,11 +1625,10 @@
if (shp->shm_nattch == 0) {
int id = shp->id;
ssi_local_destroy(shp);
- cli_ipcname_rmid(NAME_SERVICE_SHM, id);
/* ssi_local_destroy released shp.shm_perm.lock */
+ cli_ipcname_rmid(NAME_SERVICE_SHM, id);
up(&shm_ids.sem);
- }
- else {
+ } else {
shp->shm_flags |= SHM_DEST;
ipc_drop_locks(shp->id,
(struct kern_ipc_perm *)shp,
@@ -1538,13 +1649,14 @@
}
}
}
-#endif /* !IPC_SHM_LOCK_DEST_FIX */
if (cfs_shm_node_mnts[node]) {
mntput(cfs_shm_node_mnts[node]);
cfs_shm_node_mnts[node] = NULL;
}
+#endif /* !IPC_SHM_RACE_FIX */
}
+/* Called with shm_ids.sem or shp locked */
long
shm_get_segsize(struct shmid_kernel *shp)
{
@@ -1559,6 +1671,7 @@
return i_size_read(shp->shm_file->f_dentry->d_inode);
}
+/* Called with shm_ids.sem or shp locked */
long
shm_get_cpid(struct shmid_kernel *shp)
{
@@ -1623,10 +1736,16 @@
}
newid = -1;
create = size;
+#ifdef IPC_SHM_RACE_FIX
+ SSI_ASSERT(server == this_node);
+#else
up(&shm_ids.sem);
- retval = cli_ipcname_getid(NAME_SERVICE_SHM, key, shmflg, &newid,
+#endif
+ retval = cli_ipcname_getid(NAME_SERVICE_SHM, key, shmflg, &newid,
&server, ssi_get_localview(), &create);
+#ifndef IPC_SHM_RACE_FIX
down(&shm_ids.sem);
+#endif
if (!retval) {
retval = newid;
@@ -1656,9 +1775,8 @@
/* create and fill server structure */
if (shm_svr_create(shp, newid, size, key, shmflg) < 0) {
cli_ipcname_rmid(NAME_SERVICE_SHM, newid);
- shm_lock(newid);
- shp->shm_node = 0;
- shm_destroy(shp);
+ shp = shm_lock(newid);
+ ssi_local_destroy(shp);
retval = -EINVAL;
goto out_nolock;
}
@@ -1672,9 +1790,38 @@
*/
if (create) {
struct dentry *newde;
+#ifdef IPC_SHM_RACE_FIX
+ struct dentry *old_dentry;
/* go register with server, create cfs stuff */
newde = ssi_shm_setup(server, newid, size, key);
+
+ shp = shm_lock(newid);
+ if (!shp) {
+ dput(newde);
+ retval = -ESRCH;
+ goto out_nolock;
+ }
+ if (!newde) {
+ shm_destroy(shp);
+ retval = -ESRCH;
+ goto out_nolock;
+ }
+
+ /* switch file to cfs and cleanup */
+ old_dentry = shp->shm_file->f_dentry;
+ shp->shm_file->f_dentry = newde;
+ shp->shm_file->f_op = &cfs_shm_file_operations;
+ shp->shm_file->f_mapping = newde->d_inode->i_mapping;
+ shp->shm_node = server;
+ shm_unlock(shp);
+ up(&shm_ids.sem);
+
+ dput(old_dentry);
+ return retval;
+#else /* IPC_SHM_RACE_FIX */
+ /* go register with server, create cfs stuff */
+ newde = ssi_shm_setup(server, newid, size, key);
if (newde) {
/* switch file to cfs and cleanup */
dput(shp->shm_file->f_dentry);
@@ -1690,6 +1837,7 @@
retval = -ESRCH;
goto out_nolock;
}
+#endif /* !IPC_SHM_RACE_FIX */
}
}
out_nolock:
Index: util.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/util.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- util.c 13 Feb 2010 14:50:14 -0000 1.10
+++ util.c 5 Mar 2010 06:30:21 -0000 1.11
@@ -75,11 +75,6 @@
else
ids->seq_max = seq_limit;
}
-#ifdef CONFIG_SSI
-#ifdef IPC_SHM_RACE_FIX
- ids->lock_dest_id = -1;
-#endif
-#endif
ids->entries = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*size +
sizeof(struct ipc_id_ary));
@@ -234,15 +229,6 @@
if (table)
up(&ids->sem);
}
-
-#ifdef IPC_SHM_LOCK_DEST_FIX
-/* Called with ids.sem held */
-void
-ipc_lock_dest_id(struct ipc_ids *ids, int id)
-{
- ids->lock_dest_id = id; /* SHM_LOCK_DEST */
-}
-#endif
#endif /* CONFIG_SSI */
/**
@@ -272,7 +258,11 @@
#ifdef CONFIG_SSI
if (newid >= 0) {
id = newid%SEQ_MULTIPLIER;
+ /* Make ipc_checkid() pass */
ids->seq = newid/SEQ_MULTIPLIER;
+#ifdef IPC_SHM_RACE_FIX
+ BUG_ON(ids->entries->p[id] != NULL);
+#endif
goto found;
}
#endif
Index: msg.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/ipc/msg.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- msg.c 2 Feb 2010 05:19:30 -0000 1.16
+++ msg.c 5 Mar 2010 06:30:21 -0000 1.17
@@ -340,10 +340,16 @@
}
}
newid = -1;
+#ifdef IPC_SHM_RACE_FIX
+ SSI_ASSERT(server == this_node);
+#else
up(&msg_ids.sem);
+#endif
retval = cli_ipcname_getid(NAME_SERVICE_MSG, key, msgflg, &newid,
&server, ssi_get_localview(), &create);
+#ifndef IPC_SHM_RACE_FIX
down(&msg_ids.sem);
+#endif
if (!retval)
{
retval = newid;
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev