[SSI] openssi/kernel/cluster/ssi/cfs cfs_ipcshm.c, 1.23, 1.24 cfsproc.c, 1.36, 1.37

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/cluster/ssi/cfs
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv9483/kernel/cluster/ssi/cfs

Modified Files:
      Tag: OPENSSI-FC
	cfs_ipcshm.c cfsproc.c 
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: cfs_ipcshm.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/cfs/cfs_ipcshm.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- cfs_ipcshm.c	5 Mar 2010 06:25:36 -0000	1.23
+++ cfs_ipcshm.c	5 Mar 2010 06:30:21 -0000	1.24
@@ -43,15 +43,13 @@
 
 extern struct super_block *cfs_shm_sb;
 extern struct vfsmount *shm_mnt;
-#ifdef IPC_SHM_RACE_FIX
-extern struct ipc_ids shm_ids_svr;
-extern void ipc_drop_locks(int, struct kern_ipc_perm *, struct ipc_ids *, int);
-extern struct kern_ipc_perm * ipc_get_locks(int, struct ipc_ids *, int);
-#endif
 static struct super_block *shm_get_cfs_sb(clusternode_t, struct vfsmount *);
 
 struct super_block *cfs_shm_sb;
 struct vfsmount *cfs_shm_node_mnts[NSC_MAX_NODE_VALUE + 1];
+#ifdef IPC_SHM_RACE_FIX
+DEFINE_RWLOCK(cfs_shm_node_mnts_lock);
+#endif
 
 void
 cfs_shm_init(void)
@@ -73,175 +71,273 @@
 		int shmflg)
 {
 	struct shmid_kernel_svr *svr_shm;
-	nsc_nodelist_t *nl;
-	int err = 0;
 
-
-	svr_shm = (struct shmid_kernel_svr *)kmalloc(sizeof(*svr_shm),
-								GFP_KERNEL);
+#ifdef IPC_SHM_RACE_FIX
+	svr_shm = ipc_rcu_alloc(sizeof(*svr_shm));
+#else
+	svr_shm = (typeof(svr_shm)) kmalloc(sizeof(*svr_shm), GFP_KERNEL);
+#endif
 	if (!svr_shm)
 		return -ENOMEM;
 
-	svr_shm->shm_id = newid;
-	svr_shm->shm_segsz = size;
-	svr_shm->shm_cprid = current->pid;
-
 	svr_shm->shm_perm.key = key;
-	svr_shm->shm_perm.local_view = ssi_get_localview();
-	svr_shm->shm_perm.mode = (shmflg & S_IRWXUGO);
 	svr_shm->shm_perm.uid = current->euid;
-	svr_shm->shm_perm.cuid = current->euid;
 	svr_shm->shm_perm.gid = current->egid;
+	svr_shm->shm_perm.cuid = current->euid;
 	svr_shm->shm_perm.cgid = current->egid;
+	svr_shm->shm_perm.mode = (shmflg & S_IRWXUGO);
 	svr_shm->shm_perm.seq = shp->shm_perm.seq;
-	/* shm_unlock(svr_shm); */
+	svr_shm->shm_perm.local_view = ssi_get_localview();
+	svr_shm->shm_perm.security = NULL;
 
-	nl = NSC_NODELIST_ALLOC();
-	NSC_NODELIST_SET1(nl, this_node);
-	svr_shm->shm_nodelist = nl;
-	svr_shm->shm_svr =(struct svrcfstok *)makehp(cfs_shm_sb,
+	svr_shm->shm_id = newid;
+	svr_shm->shm_segsz = size;
+	svr_shm->shm_cprid = current->pid;
+
+	svr_shm->shm_nodelist = NSC_NODELIST_ALLOC();
+	NSC_NODELIST_SET1(svr_shm->shm_nodelist, this_node);
+
+	svr_shm->shm_svr = (struct svrcfstok *) makehp(cfs_shm_sb,
 			ssidev_get_s_ssidev(shm_mnt->mnt_sb, FALSE),
 			shp->shm_file->f_dentry);
-	SSI_ASSERT(svr_shm->shm_svr);
+	BUG_ON(!svr_shm->shm_svr);
+
 	if (shm_svr_addid(svr_shm) < 0) {
-		printk("failed to add shm svr\n");
+		printk(KERN_WARNING "%s:failed to add shm svr\n", __FUNCTION__);
 		HASH_RELE(svr_shm->shm_svr);
-		NSC_NODELIST_FREE(nl);
+		NSC_NODELIST_FREE(svr_shm->shm_nodelist);
+#ifdef IPC_SHM_RACE_FIX
+		ipc_rcu_putref(svr_shm);
+#else
 		kfree(svr_shm);
-		err = -EINVAL;
+#endif
+		return -EINVAL;
 	}
-	return err;
+
+	return 0;
 }
 
-struct dentry *
-ssi_shm_setup(clusternode_t server, long newid, int new, key_t key)
+/* Server is remote */
+static struct dentry *
+ssi_shm_setup_client(clusternode_t server, long newid, key_t key)
 {
-	int		status = 0;
-	struct shmid_kernel_svr *shmsvr = NULL;
-	struct inode *ip = NULL;
-	struct qstr this;
+	struct cfs_nettok res_toks[CFS_NTOKS];
+	struct cfsdiropres res;
+	struct cfslookargs args;
+	struct cfs_server dummy;
+	struct super_block *cfs_node_sb;
+	struct inode *ip;
 	struct dentry *de;
+#ifdef CFS_IPCSHM_DENTRY
+	struct dentry *alias;
+#endif
+	struct qstr this;
+	key_t getkey;
+	int get_remote, size, status = 0;
+	char name[13];
+#ifdef IPC_SHM_RACE_FIX
+	struct vfsmount *mnt;
+	char locked = 0;
+static DECLARE_MUTEX(ssi_shm_setup_lock);
+#endif
 
-	if (server == this_node) {
-		if (!new) {
-			struct shmid_kernel *shmsvr = shm_cli_get(newid);
-			if (!shmsvr)
-				return NULL;
-			if (shmsvr->shm_file->f_op != &cfs_shm_file_operations)
-				printk("shmid %ld not cfs file op yet\n",newid);
-			de = dget(shmsvr->shm_file->f_dentry);
-			return de;
-		}
+	get_remote = (cfs_shm_node_mnts[server] == NULL);
+	if (get_remote) {
 #ifdef IPC_SHM_RACE_FIX
-		ipc_get_locks(0, &shm_ids_svr, 1);
+		down(&ssi_shm_setup_lock);
+		locked = 1;
+
+		if (cfs_shm_node_mnts[server])
+			goto mounted; /* lost race */
+
+		/* Server will callback to mount remote SHM filesystem
+		 * and populate cfs_shm_node_mnts[server] on this node.
+		 */
 #endif
-		shmsvr = (struct shmid_kernel_svr *)shm_svr_get(newid);
-		if (!shmsvr) {
+		status = do_shm_server_mount(server, this_node, newid,
+						&getkey, &size);
+		if (status) {
 #ifdef IPC_SHM_RACE_FIX
-			ipc_drop_locks(0, NULL, &shm_ids_svr, 1);
+			up(&ssi_shm_setup_lock);
 #endif
 			return NULL;
 		}
-		ip = cfs_hpget(cfs_shm_sb, shmsvr->shm_svr);
-		if (ip == NULL) {
+
+		key = getkey;
+#ifdef NOTYET
+		sprintf(ssidev_buf, "%8.8x", ssidev);
+		mnt = do_kern_mount("cfs", 0, ssidev_buf, NULL);
+		cfs_shm_node_mnts[server] = mnt->mnt_sb;
+#endif
+
+	}
 #ifdef IPC_SHM_RACE_FIX
-			ipc_drop_locks(0, NULL, &shm_ids_svr, 1);
+mounted:
+	read_lock(&cfs_shm_node_mnts_lock);
+	mnt = mntget(cfs_shm_node_mnts[server]);
+	read_unlock(&cfs_shm_node_mnts_lock);
+	if (locked)
+		up(&ssi_shm_setup_lock);
+	if (!mnt)
+		return NULL; /* Lost race with nodedown */
+
+	cfs_node_sb = mnt->mnt_sb;
+#else
+	cfs_node_sb = (cfs_shm_node_mnts[server])->mnt_sb;
 #endif
-			return NULL;
-		}
-		memcpy(&this, &(shmsvr->shm_svr->sct_dp->d_name), sizeof(struct qstr));
+	dummy.mi_server = server;
+
+	sprintf(name, "SYSV%08x", key);
+	this.name = name;
+	this.len = strlen(name);
+	this.hash = 0;
+	res.cdr_res_toks = res_toks;
+	args.clua_fhandle = *itocfh(cfs_node_sb->s_root->d_inode);
+	args.clua_name = this;
+	cfstok_get_agent(&args.clua_agent);
+
+	status = rcfscall(&dummy, CFSD_PROC_LOOKUP,
+			(xdrproc_t)xdr_cfslookargs, (caddr_t)&args,
+			(xdrproc_t)xdr_cfsdiropres, (caddr_t)&res);
+	if (!status)
+		status = res.cdr_status;
+	if (!status) {
+		ip = cfs_fhget(cfs_node_sb, &(res.cdr_cdrok));
+		/* SSI_ASSERT(ip != NULL); */
+
+		status = do_shm_register(server, this_node,newid,&size);
+		if (status) {
 #ifdef IPC_SHM_RACE_FIX
-		ipc_drop_locks(0, NULL, &shm_ids_svr, 1);
+			iput(ip);
+			mntput(mnt);
 #endif
-		de = d_alloc(cfs_shm_sb->s_root, &this);
+			return NULL;
+		}
+
+		de = d_alloc(cfs_node_sb->s_root, &this);
 #ifdef CFS_IPCSHM_DENTRY
 		if (!de) {
 			iput(ip);
+#ifdef IPC_SHM_RACE_FIX
+			mntput(mnt);
+#endif
 			return NULL;
 		}
-		d_add(de, ip);
-#else
+		ip->i_size = size;
+
+		alias = d_instantiate_unique(de, ip);
+		if (alias) {
+			dput(de);
+			de = alias;
+		}
+#else /* CFS_IPCSHM_DENTRY */
 		de->d_sb = ip->i_sb;
-		de->d_parent = cfs_shm_sb->s_root;
+		de->d_parent = cfs_node_sb->s_root;
+		ip->i_size = size;
 		d_instantiate(de, ip);
-		d_rehash(shmsvr->shm_svr->sct_dp);
+#endif /* !CFS_IPCSHM_DENTRY */
+#ifdef JUNK
+		shp->shm_file->f_dentry = de;
+		shp->shm_file->f_op = &cfs_shm_file_operations;
+		dput(newde);
+#endif
+#ifdef IPC_SHM_RACE_FIX
+		mntput(mnt);
 #endif
 		return de;
 	}
-	else {
-		struct cfs_nettok res_toks[CFS_NTOKS];
-		struct cfsdiropres res;
-                struct cfslookargs args;
-		int get_remote;
-		struct super_block *cfs_node_sb;
-		struct cfs_server dummy;
-		key_t getkey;
-		int size;
-		char name[13];
-
-		get_remote = (cfs_shm_node_mnts[server] == NULL);
-		if (get_remote) {
 
-			status = do_shm_server_mount(server, this_node, newid,
-							&getkey, &size);
-			if (status)
-				return NULL;
+	return NULL;
+}
 
-			key = getkey;
-#ifdef NOTYET
-			sprintf(ssidev_buf, "%8.8x", ssidev);
-			mnt = do_kern_mount("cfs", 0, ssidev_buf, NULL);
-			cfs_shm_node_mnts[server] = mnt->mnt_sb;
+static struct dentry *
+ssi_shm_setup_new(long newid)
+{
+	struct qstr this;
+	struct inode *ip;
+	struct dentry *de;
+	struct shmid_kernel_svr *shmsvr;
+#ifdef CFS_IPCSHM_DENTRY
+	struct dentry *res;
 #endif
+#ifdef IPC_SHM_RACE_FIX
+	struct svrcfstok *hp;
 
-		}
-		cfs_node_sb = (cfs_shm_node_mnts[server])->mnt_sb;
-		dummy.mi_server = server;
-
-		sprintf(name, "SYSV%08x", key);
-		this.name = name;
-		this.len = strlen(name);
-		this.hash = 0;
-		res.cdr_res_toks = res_toks;
-		args.clua_fhandle = *itocfh(cfs_node_sb->s_root->d_inode);
-		args.clua_name = this;
-		cfstok_get_agent(&args.clua_agent);
+	shmsvr = shm_svr_lock(newid);
+	if (!shmsvr)
+		return NULL;
+	hp = shmsvr->shm_svr;
+	HASH_HOLD(hp);
+	shm_svr_unlock(shmsvr);
 
-		status = rcfscall(&dummy, CFSD_PROC_LOOKUP,
-				(xdrproc_t)xdr_cfslookargs, (caddr_t)&args,
-				(xdrproc_t)xdr_cfsdiropres, (caddr_t)&res);
-		if (!status)
-			status = res.cdr_status;
-		if (!status) {
-			ip = cfs_fhget(cfs_node_sb, &(res.cdr_cdrok));
-			SSI_ASSERT(ip != NULL);
-		
-			status = do_shm_register(server, this_node,newid,&size);
-			if (status)
-				return NULL;
+	ip = cfs_hpget(cfs_shm_sb, hp);
+	if (ip == NULL) {
+		HASH_RELE(hp);
+		return NULL;
+	}
+	memcpy(&this, &hp->sct_dp->d_name, sizeof(struct qstr));
+	HASH_RELE(hp);
+#else
+	shmsvr = (struct shmid_kernel_svr *)shm_svr_get(newid);
+	if (!shmsvr)
+		return NULL;
+	ip = cfs_hpget(cfs_shm_sb, shmsvr->shm_svr);
+	if (ip == NULL)
+		return NULL;
+	memcpy(&this, &shmsvr->shm_svr->sct_dp->d_name, sizeof(struct qstr));
+#endif /* !IPC_SHM_RACE_FIX */
 
-			de = d_alloc(cfs_node_sb->s_root, &this);
+	de = d_alloc(cfs_shm_sb->s_root, &this);
 #ifdef CFS_IPCSHM_DENTRY
-			if (!de) {
-				iput(ip);
-				return NULL;
-			}
+	if (!de) {
+		iput(ip);
+		return NULL;
+	}
+
+	res = d_add_unique(de, ip);
+	if (res) {
+		dput(de);
+		de = res;
+	}
 #else
-			de->d_sb = ip->i_sb;
-			de->d_parent = cfs_node_sb->s_root;
-#endif
-			ip->i_size = size;
-			d_instantiate(de, ip);
-#ifdef JUNK
-			shp->shm_file->f_dentry = de;
-			shp->shm_file->f_op = &cfs_shm_file_operations;
-			dput(newde);
+	de->d_sb = ip->i_sb;
+	de->d_parent = cfs_shm_sb->s_root;
+	d_instantiate(de, ip);
+	d_rehash(shmsvr->shm_svr->sct_dp);
+#endif /* !CFS_IPCSHM_DENTRY */
+	return de;
+}
+
+struct dentry *
+ssi_shm_setup(clusternode_t server, long newid, int new, key_t key)
+{
+	struct shmid_kernel *shp;
+	struct dentry *de;
+
+	if (server != this_node)
+		return ssi_shm_setup_client(server, newid, key);
+
+	/* SSI_ASSERT(server == this_node); */
+	if (new)
+		return ssi_shm_setup_new(newid);
+
+#ifdef IPC_SHM_RACE_FIX
+	shp = shm_cli_lock(newid);
+#else
+	shp = shm_cli_get(newid);
 #endif
-			return de;
-		}
-	}
+	if (!shp)
+		return NULL;
 
-	return NULL;
+	if (shp->shm_file->f_op != &cfs_shm_file_operations) {
+		printk(KERN_WARNING "%s: shmid %ld not "
+			"cfs file op yet\n", __FUNCTION__, newid);
+	}
+	de = dget(shp->shm_file->f_dentry);
+#ifdef IPC_SHM_RACE_FIX
+	shm_cli_unlock(shp);
+#endif
+	return de;
 }
 
 static struct super_block *
@@ -307,7 +403,28 @@
 	HASH_RELE(shmsvr->shm_svr);
 }
 
-/* Caller must hold shm_ids.sem or shm_ids_svr.sem */
+#ifdef IPC_SHM_RACE_FIX
+struct inode *
+shm_svr_grab_inode(int id)
+{
+	struct shmid_kernel_svr *shmsvr;
+	struct inode *inode;
+
+	shmsvr = shm_svr_lock(id);
+	if (!shmsvr)
+		return NULL;
+	inode = shmsvr->shm_svr->sct_ip;
+	if (inode)
+		atomic_inc(&inode->i_count);
+	shm_svr_unlock(shmsvr);
+	return inode;
+}
+#endif /* IPC_SHM_RACE_FIX */
+
+/*
+ * Caller must hold shm_ids.sem or shmid_kernel_svr->shm_perm.lock
+ * if dereferencing returned inode. Otherwise use shm_svr_grab_inode().
+ */
 struct inode *
 shm_svr_get_inode(int id)
 {
@@ -340,17 +457,13 @@
 		return ERR_PTR(error);
 
 #ifdef IPC_SHM_RACE_FIX
-	ipc_get_locks(0, &shm_ids_svr, 1);
-#endif
+	inode = shm_svr_grab_inode(id);
+	if (!inode)
+		return ERR_PTR(-EACCES);
+#else
 	inode = shm_svr_get_inode(id);
-	if (!inode || !igrab(inode)) {
-#ifdef IPC_SHM_RACE_FIX
-		ipc_drop_locks(0, NULL, &shm_ids_svr, 1);
-#endif
+	if (!inode || !igrab(inode))
 		return ERR_PTR(-EACCES);
-	}
-#ifdef IPC_SHM_RACE_FIX
-	ipc_drop_locks(0, NULL, &shm_ids_svr, 1);
 #endif
 
 	return d_splice_alias(inode, dentry);
@@ -361,20 +474,31 @@
 {
 	int i;
 
-	if (!strncmp(de->d_name.name, "SYSV", 4)) {
-		if (is_pfs) {
-			if (de->d_inode)
-				return is_shmem_inode(de->d_inode);
-			/* negative lookup */
-			return (de->d_sb == (cfs_shm_node_mnts[this_node])->mnt_root->d_sb);
-		}
-		for (i=1; i <= (NSC_MAX_NODE_VALUE + 1); i++) {
-			if (!cfs_shm_node_mnts[i])
-				continue;
-			if (de->d_sb == (cfs_shm_node_mnts[i])->mnt_sb)
-				return 1;
+	if (strncmp(de->d_name.name, "SYSV", 4))
+		return 0;
+
+	if (is_pfs) {
+		if (de->d_inode)
+			return is_shmem_inode(de->d_inode);
+		/* negative lookup */
+		return (de->d_sb ==
+			(cfs_shm_node_mnts[this_node])->mnt_root->d_sb);
+	}
+#ifdef IPC_SHM_RACE_FIX
+	read_lock(&cfs_shm_node_mnts_lock);
+#endif
+	for (i=1; i <= (NSC_MAX_NODE_VALUE + 1); i++) {
+		if (!cfs_shm_node_mnts[i])
+			continue;
+		if (de->d_sb == (cfs_shm_node_mnts[i])->mnt_sb) {
+#ifdef IPC_SHM_RACE_FIX
+			read_unlock(&cfs_shm_node_mnts_lock);
+#endif
+			return 1;
 		}
 	}
-
+#ifdef IPC_SHM_RACE_FIX
+	read_unlock(&cfs_shm_node_mnts_lock);
+#endif
 	return 0;
 }

Index: cfsproc.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/cfs/cfsproc.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- cfsproc.c	17 Dec 2009 06:43:50 -0000	1.36
+++ cfsproc.c	5 Mar 2010 06:30:21 -0000	1.37
@@ -1310,7 +1310,13 @@
 	data.payload = argp;
 	sprintf(ssidev_buffer, "%8.8x", argp->ssidev);
 	mnt =  do_kern_mount("cfs", 0, ssidev_buffer, &data);
+#ifdef IPC_SHM_RACE_FIX
+	write_lock(&cfs_shm_node_mnts_lock);
+	cfs_shm_node_mnts[argp->server] = mnt;
+	write_unlock(&cfs_shm_node_mnts_lock);
+#else
 	cfs_shm_node_mnts[argp->server] = mnt;
+#endif
 	return;
 }
 


------------------------------------------------------------------------------
Download Intel&#174; 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