[SSI] openssi/kernel/cluster/ssi/util load_level.c, 1.25, 1.26 nfs_mount.c, 1.13, 1.14 rcopy.c, 1.13, 1.14 rmtfb.c, 1.24, 1.25 ssipty.c, 1.15, 1.16

Roger Tsang <[email protected]>
Newsgroups gmane.linux.cluster.ssic.cvs
Message-ID <[email protected]>
Update of /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/util
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv1388/cluster/ssi/util

Modified Files:
      Tag: OPENSSI-FC
	load_level.c nfs_mount.c rcopy.c rmtfb.c ssipty.c 
Log Message:
Multiple bug fixes. See ChangeLog.


Index: nfs_mount.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/util/nfs_mount.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- nfs_mount.c	27 Oct 2009 03:18:29 -0000	1.13
+++ nfs_mount.c	17 Dec 2009 06:43:51 -0000	1.14
@@ -409,6 +409,7 @@
 	struct nfs_vfsmount_data *cmdp;
 	int p_len;
 
+	*type = NULL;
 	*payload = NULL;
 
 	p_len = sizeof(struct nfs_vfsmount_data);
@@ -425,6 +426,7 @@
 	*payload = kmalloc(*payload_len, GFP_KERNEL);
 	if (*payload == NULL) {
 		kfree(*type);
+		*type = NULL;
 		return -ENOMEM;
 	}
 

Index: ssipty.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/util/ssipty.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- ssipty.c	27 Oct 2009 03:18:29 -0000	1.15
+++ ssipty.c	17 Dec 2009 06:43:51 -0000	1.16
@@ -1199,6 +1199,7 @@
 	umode_t mode;
 	int p_len;
 
+	*type = NULL;
 	*payload = NULL;
 
 	/* Ignore local only vfsmount */
@@ -1219,6 +1220,7 @@
 	*payload = kmalloc(*payload_len, GFP_KERNEL);
 	if (*payload == NULL) {
 		kfree(*type);
+		*type = NULL;
 		return -ENOMEM;
 	}
 
@@ -1243,8 +1245,13 @@
 	ssipty_get_mntopts(&setuid, &uid, &setgid, &gid, &mode);
 	ret = ssipty_build_mntopts(cmap, cmap_len, setuid, uid, setgid, gid,
 				   mode);
-	if (ret < 0)
+	if (ret < 0) {
+		kfree(*payload);
+		*payload = NULL;
+		kfree(*type);
+		*type = NULL;
 		return ret;
+	}
 
 	return 0;
 }

Index: load_level.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/util/load_level.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- load_level.c	17 Nov 2009 06:09:02 -0000	1.25
+++ load_level.c	17 Dec 2009 06:43:51 -0000	1.26
@@ -806,11 +806,7 @@
 			else {
 #endif /* !LOADLEVEL_TABLE_LIST */
 				/* get process executable from its memory */
-				task_lock(p);
-				mm = p->mm;
-				if (mm)
-					atomic_inc(&mm->mm_users);
-				task_unlock(p);
+				mm = get_task_mm(p);
 				if (!mm)
 					return 0;
 
@@ -821,13 +817,14 @@
 				vma = mm->mmap;
 				while (vma) {
 					if ((vma->vm_flags & VM_EXECUTABLE) &&
-					    vma->vm_file) {
-						mnt = mntget(vma->vm_file->f_vfsmnt);
-						dentry = dget(vma->vm_file->f_dentry);
+					    vma->vm_file)
 						break;
-					}
 					vma = vma->vm_next;
 				}
+				if (vma) {
+					mnt = mntget(vma->vm_file->f_vfsmnt);
+					dentry = dget(vma->vm_file->f_dentry);
+				}
 				up_read(&mm->mmap_sem);
 				mmput(mm);
 			}

Index: rmtfb.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/util/rmtfb.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- rmtfb.c	27 Oct 2009 03:18:29 -0000	1.24
+++ rmtfb.c	17 Dec 2009 06:43:51 -0000	1.25
@@ -107,18 +107,28 @@
  * Support Routines
  */
 
-static inline struct inode *
-ftoi(struct file *file)
-{
-	return file->f_dentry->d_inode;
-}
+#define GET_RFB(_rfb) atomic_inc(&(_rfb)->rfb_refcnt)
 
-static inline struct rmtfb_cli *
+#define ftoi(_fp) ((_fp)->f_dentry->d_inode)
+
+#ifndef RMTFB_REFCNT_FIX
+static inline
+#endif
+struct rmtfb_cli *
 ftocli(struct file *file)
 {
-	struct rmtfb_cli *rfb = (struct rmtfb_cli *)file->private_data;
-	rfb = (rfb && rfb->rfb_magic == rmtfb_magic) ? rfb : NULL;
-	SSI_ASSERT(!rfb || rfb->common.rfb_file == file);
+	struct rmtfb_cli *rfb;
+
+	if (!file->private_data)
+		return NULL;
+
+	rfb = (struct rmtfb_cli *)file->private_data;
+	SSI_ASSERT(rfb);
+	if (!rfb)
+		return NULL;
+	if (rfb->rfb_magic != rmtfb_magic)
+		return NULL;
+	SSI_ASSERT(rfb->common.rfb_file == file);
 	return rfb;
 }
 
@@ -174,6 +184,18 @@
 	kfree(rfb);
 }
 
+#ifdef RMTFB_REFCNT_FIX
+static inline void
+rmtfb_freecli(struct rmtfb_cli *rfb)
+{
+	/* SSI: We skipped struct file reference to avoid circular reference.
+	 *	file->private_data->common.rfb_file == file
+	 */
+	/* fput(rfb->common.rfb_file); */
+	rfb->rfb_magic = 0;
+	kfree(rfb);
+}
+#endif
 
 /*
  * Client Bitmap
@@ -184,31 +206,35 @@
 rmtfb_set_bit(clusternode_t cli, struct rmtfb_svr *rfb, int set)
 {
 	SSI_ASSERT(cli && !inval(1,cli));
-	if (set) {
 #ifdef RMTFB_REFCNT_FIX
-		atomic_inc(&rfb->rfb_refcnt);
-#endif
+	if (set) {
+		if (!test_and_set_bit(cli - 1, rfb->rfb_clients))
+			GET_RFB(rfb);
+	} else {
+		if (test_and_clear_bit(cli - 1, rfb->rfb_clients))
+			rmtfb_putsvr(rfb);
+	}
+#else
+	if (set) {
 		set_bit(cli - 1, &rfb->rfb_clients[0]);
 	} else {
 		clear_bit(cli - 1, &rfb->rfb_clients[0]);
-#ifdef RMTFB_REFCNT_FIX
-		rmtfb_putsvr(rfb);
-#endif
 	}
+#endif /* !RMTFB_REFCNT_FIX */
 }
 
+#ifndef RMTFB_REFCNT_FIX
 static inline int
 rmtfb_nocli(struct rmtfb_svr *rfb)
 {
-#ifndef RMTFB_REFCNT_FIX
 	int ctr = 0;
 	volatile unsigned long *word = rfb->rfb_clients;
 	for (; ctr < rfb_clients_len; ++ctr, ++word)
 		if (*word)
 			return 0;
-#endif
 	return 1;
 }
+#endif
 
 int
 rmtfb_setopen(
@@ -246,6 +272,7 @@
 	}
 	rmtfb_putsvr(rfb);
 	error = 0;
+	/* file already held by rfb */
 file_out:
 	fput(file);
 out:
@@ -467,11 +494,16 @@
 static void
 rmtfb_clrnode(struct rmtfb_cmn *cmn, u_long arg)
 {
+	struct rmtfb_svr *rfb = (struct rmtfb_svr *)cmn;
 	struct rmtfb_clrnode_arg *ap = (void *)arg;
 
-	struct rmtfb_svr *rfb = (struct rmtfb_svr *)cmn;
+#ifdef RMTFB_REFCNT_FIX
+	if (test_bit(ap->node - 1, rfb->rfb_clients)) {
+		GET_RFB(rfb);
+		list_move(&rfb->common.rfb_hash, ap->list);
+	}
+#else
 	rmtfb_set_bit(ap->node, rfb, 0);
-#ifndef RMTFB_REFCNT_FIX
 	if (!atomic_read(&rfb->rfb_refcnt) && rmtfb_nocli(rfb))
 		list_move(&rfb->common.rfb_hash, ap->list);
 #endif
@@ -507,11 +539,13 @@
 		clusternode_t surrogate,
 		void *private)
 {
-#ifndef RMTFB_REFCNT_FIX
+#ifdef RMTFB_REFCNT_FIX
+	struct rmtfb_svr *rfb, *tmp;
+#else
 	struct list_head *cur;
+#endif
 	LIST_HEAD(freelist);
 	struct rmtfb_clrnode_arg rca;
-#endif
 
 	SSI_ASSERT(node && !inval(1,node));
 
@@ -521,17 +555,18 @@
 	rmtfb_nodedown_cmn(rmtfb_clitbl, rmtfb_badops, (u_long)node);
 	UNLOCK_SHR_RW_LOCK(&rmtfb_clitbl_lock);
 
-#ifdef RMTFB_REFCNT_FIX
-	LOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
-	rmtfb_nodedown_cmn(rmtfb_svrtbl, rmtfb_clrnode, 0);
-	UNLOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
-#else
 	rca.node = node;
 	rca.list = &freelist;
 	LOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
 	rmtfb_nodedown_cmn(rmtfb_svrtbl, rmtfb_clrnode, (u_long)&rca);
 	UNLOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
 
+#ifdef RMTFB_REFCNT_FIX
+	list_for_each_entry_safe(rfb, tmp, &freelist, common.rfb_hash) {
+		rmtfb_set_bit(node, rfb, 0);
+		rmtfb_putsvr(rfb);
+	}
+#else
 	list_for_each(cur, &freelist) {
 		struct rmtfb_svr *rfb = (struct rmtfb_svr *)
 			list_entry(cur, struct rmtfb_cmn, rfb_hash);
@@ -584,19 +619,21 @@
 		void *data)
 {
 	struct rmtfb_svr *rfb;
+
 #ifdef RFBDEBUG
 	printk(KERN_DEBUG "rmtfb_getsvr: pid=%d searching for ino=%lu\n",
 				current->pid, ino);
 #endif
 	SSI_ASSERT_LOCKED_SHR_RW_LOCK(&rmtfb_svrtbl_lock);
+
 	rfb = (struct rmtfb_svr *) rmtfb_getcmn(
 					&rmtfb_svrtbl[hash(ino)],
 					test,
 					data);
 	if (rfb)
-		atomic_inc(&rfb->rfb_refcnt);
-	SSI_ASSERT(!rfb || atomic_read(&rfb->rfb_refcnt));
+		GET_RFB(rfb);
 #ifdef RFBDEBUG
+	SSI_ASSERT(!rfb || atomic_read(&rfb->rfb_refcnt));
 	rmtfb_svr_debug("rmtfb_getsvr:",rfb);
 #endif
 	return rfb;
@@ -605,18 +642,26 @@
 struct rmtfb_svr *
 rmtfb_getsvr_file(struct file *file)
 {
-	struct rmtfb_svr *rfb = NULL;
+	struct rmtfb_svr *rfb;
+
 	SSI_ASSERT(file);
+
+#ifndef RMTFB_REFCNT_FIX
 	if (atomic_read(&file->f_count) > 1) {
+#endif
 		LOCK_SHR_RW_LOCK(&rmtfb_svrtbl_lock);
 		rfb = rmtfb_getsvr(
 				ftoi(file)->i_ino,
 				rmtfb_test_file,
 				(void *)file);
 		UNLOCK_SHR_RW_LOCK(&rmtfb_svrtbl_lock);
-	}
+#ifndef RMTFB_REFCNT_FIX
+	} else
+		rfb = NULL;
+#endif
 	if (!rfb)
 		rfb = rmtfb_newsvr(file, 0, 0);
+
 	SSI_ASSERT(rfb);
 	SSI_ASSERT(IS_ERR(rfb) || rfb->common.rfb_file == file);
 	return rfb;
@@ -677,14 +722,11 @@
 #ifndef RMTFB_REFCNT_FIX
 	/* SSI_XXX: does rfb_refcnt go negative when !rmtfb_nocli() ? */
 	SSI_ASSERT(atomic_read(&rfb->rfb_refcnt));
-#endif
 	LOCK_SHR_RW_LOCK(&rmtfb_svrtbl_lock);
 	if (atomic_dec_and_test(&rfb->rfb_refcnt) && rmtfb_nocli(rfb)) {
 		atomic_inc(&rfb->rfb_refcnt);
 		UNLOCK_SHR_RW_LOCK(&rmtfb_svrtbl_lock);
-#ifndef RMTFB_REFCNT_FIX
 		SSI_ASSERT(atomic_read(&rfb->rfb_refcnt));
-#endif
 		LOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
 		if (atomic_dec_and_test(&rfb->rfb_refcnt) && rmtfb_nocli(rfb)) {
 			list_del(&rfb->common.rfb_hash);
@@ -696,15 +738,40 @@
 	}
 	else
 		UNLOCK_SHR_RW_LOCK(&rmtfb_svrtbl_lock);
+#else /* !RMTFB_REFCNT_FIX */
+	LOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
+	if (!atomic_dec_and_test(&rfb->rfb_refcnt)) {
+		UNLOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
+		return;
+	}
+	list_del(&rfb->common.rfb_hash);
+	UNLOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
+	rmtfb_freesvr(rfb);
+#endif /* RMTFB_REFCNT_FIX */
 }
 
 struct rmtfb_cli *
 rmtfb_getcli_file(struct file *file)
 {
+#ifdef RMTFB_REFCNT_FIX
+	struct rmtfb_cli *rfb;
+#endif
+
 	if (file->f_op != &ssidev_remote_fops && file->f_op != &ssidev_bad_fops)
 		return NULL;
 
+#ifdef RMTFB_REFCNT_FIX
+	rfb = ftocli(file);
+	if (!rfb)
+		return NULL;
+
+	/* No race here. file->private_data has rfb reference */
+	GET_RFB(rfb);
+
+	return rfb;
+#else
 	return ftocli(file);
+#endif /* !RMTFB_REFCNT_FIX */
 }
 
 static inline struct rmtfb_cli *
@@ -718,12 +785,22 @@
 					&rmtfb_clitbl[hash(id)],
 					rmtfb_test_id,
 					(void *)&id);
+#ifdef RMTFB_REFCNT_FIX
+	if (rfb) {
+		SSI_ASSERT(rfb->common.rfb_id == id);
+		if (!atomic_test_and_add(1, &rfb->common.rfb_file->f_count)) {
+			/* Lost race with fput() */
+			return ERR_PTR(-ERFB_RELEASE);
+		}
+		GET_RFB(rfb);
+	}
+#else
 	SSI_ASSERT(!rfb || rfb->common.rfb_id == id);
 	if (rfb && !atomic_test_and_add(1, &rfb->common.rfb_file->f_count))
 		rfb = ERR_PTR(-ERFB_RELEASE);
 	else
 		SSI_ASSERT(!rfb || atomic_read(&rfb->common.rfb_file->f_count));
-
+#endif
 	return rfb;
 }
 
@@ -793,8 +870,8 @@
 	}
 
 	/* make socket back pointer */
-	if (file->f_dentry->d_inode->i_sock) {
-		struct socket *sock = SOCKET_I(file->f_dentry->d_inode);
+	if (ftoi(file)->i_sock) {
+		struct socket *sock = SOCKET_I(ftoi(file));
 		sock->file = file;
 #ifdef SSI_SOCK_REOP_TYPE
 		sock->type = socket_type;
@@ -803,24 +880,39 @@
 		sock->ssi_rfb_svr = svr;
 	}
 
-	rfb = ERR_PTR(-EOPNOTSUPP);
 	if (file->private_data) {
 		printk(KERN_ERR
 			"rmtfb_getcli_id: non-exportable filesystem (%s)\n",
 			file->f_vfsmnt->mnt_sb->s_type->name);
-		put_filp(file);
+		fput(file);
+		rfb = ERR_PTR(-EOPNOTSUPP);
 		goto out;
 	}
 
 	rfb = rmtfb_newcli(file, id, svr, 0);
 	if (IS_ERR(rfb))
-		put_filp(file);
+		fput(file);
 out:
 	SSI_ASSERT(rfb);
 	SSI_ASSERT(IS_ERR(rfb) || rfb->common.rfb_id == id);
 	return rfb;
 }
 
+#ifdef RMTFB_REFCNT_FIX
+void rmtfb_putcli(struct rmtfb_cli *rfb)
+{
+	BUG_ON(rfb->rfb_magic != rmtfb_magic);
+	LOCK_EXCL_RW_LOCK(&rmtfb_clitbl_lock);
+	if (!atomic_dec_and_test(&rfb->rfb_refcnt)) {
+		UNLOCK_EXCL_RW_LOCK(&rmtfb_clitbl_lock);
+		return;
+	}
+	list_del(&rfb->common.rfb_hash);
+	UNLOCK_EXCL_RW_LOCK(&rmtfb_clitbl_lock);
+	rmtfb_freecli(rfb);
+}
+#endif
+
 
 /*
  * Constructors/Destructors
@@ -830,14 +922,16 @@
 rmtfb_new_prep(struct file *file, unsigned long id, size_t size)
 {
 	struct rmtfb_cmn *cmn;
+
 	SSI_ASSERT(file);
 	SSI_ASSERT(size > sizeof(*cmn));
+
 	cmn = kzmalloc(size, GFP_USER);
 	if (!cmn)
 		return NULL;
 
 	INIT_LIST_HEAD(&cmn->rfb_hash);
-	cmn->rfb_file = file;
+	cmn->rfb_file = file; /* Caller to grab reference to file */
 	cmn->rfb_id = id ? id : unum_getnum(unum_rmtfbid);
 	return cmn;
 }
@@ -848,19 +942,20 @@
 	struct rmtfb_svr *rfb, *newrfb;
 	unsigned long ino = ftoi(file)->i_ino;
 	char export = id ? 0 : 1;
-	int error;
+	int error = -ENOMEM;
 
-	SSI_ASSERT(file);
 	SSI_ASSERT(!inval(1,cli));
-	error = -ENOMEM;
+
 	newrfb = (struct rmtfb_svr *)rmtfb_new_prep(file, id, sizeof(*rfb));
 	if (!newrfb)
 		goto fail;
+
 	atomic_set(&newrfb->rfb_refcnt, 1);
 	if (cli)
 		rmtfb_set_bit(cli, newrfb, 1);
 
 	LOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
+
 	SSI_ASSERT(!ftocli(file));
 	if (export) {
 		/* make sure another export didn't make one already */
@@ -877,6 +972,7 @@
 	rmtfb_svr_debug("rmtfb_newsvr:",rfb);
 #endif
 	return rfb;
+
 unlock_free_out:
 	UNLOCK_EXCL_RW_LOCK(&rmtfb_svrtbl_lock);
 	kfree(newrfb);
@@ -935,14 +1031,17 @@
 	char import = id ? 1 : 0;
 	int error, loop = 0;
 
-	SSI_ASSERT(file);
 	SSI_ASSERT(svr && !inval(1,svr));
 
 	error = -ENOMEM;
 	newrfb = (struct rmtfb_cli *)rmtfb_new_prep(file, id, sizeof(*rfb));
 	if (!newrfb)
 		goto fail;
+
 	id = newrfb->common.rfb_id;
+#ifdef RMTFB_REFCNT_FIX
+	atomic_set(&newrfb->rfb_refcnt, 1);
+#endif
 	newrfb->rfb_magic = rmtfb_magic;
 	newrfb->rfb_server = svr;
 
@@ -975,8 +1074,15 @@
 		}
 		if (rfb) {
 			UNLOCK_EXCL_RW_LOCK(&rmtfb_clitbl_lock);
+#ifdef RMTFB_REFCNT_FIX
+			rmtfb_freecli(newrfb);
+			/* Release reference in rmtfb_getcli_id_lckd() */
+			SSI_ASSERT(rfb->common.rfb_file == file);
+			fput(rfb->common.rfb_file);
+#else
 			kfree(newrfb);
 			put_filp(file);
+#endif
 			goto out;
 		}
 	}
@@ -984,10 +1090,20 @@
 	if (!noremote)
 		rmtfb_remote_tty_ino(file, svr);
 #endif
+	/* SSI_XXX: overrides struct socket->file->f_op */
 	file->f_op = &ssidev_remote_fops;
 	file->private_data = rfb = newrfb;
+#ifdef RMTFB_REFCNT_FIX
+	/* SSI: fifo_open() will override f_op.
+	 * free_pipe_info() will release rfb reference.
+	 */
+	GET_RFB(rfb); /* for file->private_data */
+#endif
 	list_add(&rfb->common.rfb_hash, &rmtfb_clitbl[hash(id)]);
 	SSI_ASSERT(ftocli(file) == rfb);
+	/* Skipped get_file(file) due to circular reference.
+	 *	file->private_data->common.rfb_file == file
+	 */
 	UNLOCK_EXCL_RW_LOCK(&rmtfb_clitbl_lock);
 	error = 0;
 out:
@@ -996,8 +1112,13 @@
 	rmtfb_cli_debug("rmtfb_newcli:",rfb);
 #endif
 	return rfb;
+
 free_fail:
+#ifdef RMTFB_REFCNT_FIX
+	rmtfb_freecli(newrfb);
+#else
 	kfree(newrfb);
+#endif
 fail:
 #ifdef RFBDEBUG
 	printk(KERN_DEBUG "rmtfb_newcli: fail error=%d ino=%lu name=%s", error,
@@ -1016,7 +1137,16 @@
 		current->pid, file, svr);
 #endif
 	rfb = rmtfb_newcli(file, 0, svr, 0);
+#ifdef RMTFB_REFCNT_FIX
+	if (IS_ERR(rfb))
+		return PTR_ERR(rfb);
+
+	rmtfb_putcli(rfb);
+	/* rfb is still held by file->private_data */
+	return 0;
+#else
 	return IS_ERR(rfb) ? PTR_ERR(rfb) : 0;
+#endif
 }
 
 int
@@ -1047,11 +1177,17 @@
 		rmtfb_cli_debug("rmtfb_rclose:",rfb);
 #endif /* RFBDEBUG */
 
+#ifdef RMTFB_REFCNT_FIX
+	file->private_data = NULL;
+	/* Release file->private_data */
+	rmtfb_putcli(rfb);
+#else
 	LOCK_EXCL_RW_LOCK(&rmtfb_clitbl_lock);
 	list_del(&rfb->common.rfb_hash);
 	UNLOCK_EXCL_RW_LOCK(&rmtfb_clitbl_lock);
 	rfb->rfb_magic = 0;
 	kfree(rfb);
+#endif /* !RMTFB_REFCNT_FIX */
 
 	return error;
 }

Index: rcopy.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/util/rcopy.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- rcopy.c	27 Oct 2009 03:18:29 -0000	1.13
+++ rcopy.c	17 Dec 2009 06:43:51 -0000	1.14
@@ -54,40 +54,42 @@
 
 static int ssi_rcopy_strnlen_task(struct task_struct *p, u_long from, u_long *n)
 {
-	int error = 0;
 	char *cbuf;
 	u_long nbytes;
-	int copy;
-	int copied;
-	int len;
+	int error;
+	int copy, copied, len;
 
 	nbytes = *n;
 	*n = 0;
+
 	cbuf = (char *)__get_free_page(GFP_USER);
-	if (cbuf != NULL) {
-		while (nbytes > 0) {
-			if (nbytes > PAGE_SIZE)
-				copy = PAGE_SIZE;
-			else
-				copy = nbytes;
-			copied = access_process_vm(p, from, cbuf, copy, 0);
-			if (copied > 0) {
-				len = strnlen(cbuf, copied);
-				*n += len;
-				if (len < copied)
-					break;
-			}
-			if (copied != copy) {
-				error = -EFAULT;
+	if (!cbuf)
+		return -ENOMEM;
+
+	error = 0;
+	copy = PAGE_SIZE;
+	while (nbytes > 0) {
+		if (nbytes < PAGE_SIZE)
+			copy = nbytes;
+
+		copied = access_process_vm(p, from, cbuf, copy, 0);
+		if (copied > 0) {
+			len = strnlen(cbuf, copied);
+			*n += len;
+			if (len < copied)
 				break;
-			}
-			from += copied;
-			nbytes -= copied;
 		}
-		free_page((u_long)cbuf);
-		(*n)++;
-	} else
-		error = -ENOMEM;
+		if (copied != copy) {
+			error = -EFAULT;
+			break;
+		}
+		from += copied;
+		nbytes -= copied;
+	}
+	rmb(); /* control dependency */
+	(*n)++;
+
+	free_page((u_long)cbuf);
 
 	return error;
 }
@@ -98,17 +100,64 @@
 	register struct vproc *v = VPROCPTR(pid);
 	struct task_struct *p;
 	int copied;
+#ifdef TASK_HOLD_VPROC
+	void *buf;
+#endif
 
 	SSI_ASSERT(v != NULL);
 	SSI_ASSERT(*data_len > 0);
 	SSI_ASSERT(*data_len <= ICS_MAX_OOL_DATA_SIZE);
+
+#ifdef TASK_HOLD_VPROC
+	if (unlikely(v == NULL)) {
+		*rerror = -ESRCH;
+		*data_len = 0;
+		return 0;
+	}
+
+	VPROC_LOCK_FLAG(v, "rssi_rcopy_from_user");
+
+	if (unlikely(!(PVP(v)->pvp_flag & PV_IS_LOCAL))) {
+		/* Process migrated */
+		VPROC_UNLOCK_FLAG(v, "rssi_rcopy_from_user");
+		*rerror = -ESRCH;
+		*data_len = 0;
+		p = NULL;
+		goto out;
+	}
+	p = PVP(v)->pvp_pproc;
+	get_task_struct(p);
+	VPROC_UNLOCK_FLAG(v, "rssi_rcopy_from_user");
+
+	buf = *data;
+	if (!buf) {
+		buf = kmalloc(*data_len, GFP_USER);
+		if (buf == NULL) {
+			*rerror = -ENOMEM;
+			*data_len = 0;
+			goto out;
+		}
+		*data = buf;
+	}
+
+	/* Caller responsible for range check */
+	copied = access_process_vm(p, from, buf, *data_len, 0);
+	if (copied != *data_len) {
+		*data_len = copied;
+		*rerror = -EFAULT;
+	} else
+		*rerror = 0;
+
+out:
+	if (p)
+		put_task_struct(p);
+#ifdef VPROC_RELEASE__REFCNT_RACE_FIX
+	VPROC_RELE(v, "rssi_rcopy_from_user");
+#endif
+#else /* TASK_HOLD_VPROC */
 	if (v != NULL) {
 		p = PVP(v)->pvp_pproc;
-#ifdef TASK_HOLD_VPROC
-		SSI_ASSERT(PVP(v)->pvp_flag & PV_IS_LOCAL);
-#else
 		SSI_ASSERT(p != NULL);
-#endif
 	}
 	else
 		p = NULL;
@@ -135,6 +184,7 @@
 	if (v)
 		VPROC_RELE(v, "rssi_rcopy_from_user");
 #endif
+#endif /* !TASK_HOLD_VPROC */
 
 	return 0;
 }
@@ -151,13 +201,43 @@
 	SSI_ASSERT(data != NULL);
 	SSI_ASSERT(data_len > 0);
 	SSI_ASSERT(data_len <= ICS_MAX_OOL_DATA_SIZE);
+
+#ifdef TASK_HOLD_VPROC
+	if (unlikely(v == NULL))
+		goto out_bad;
+
+	VPROC_LOCK_FLAG(v, "rssi_rcopy_to_user");
+
+	if (unlikely(!(PVP(v)->pvp_flag & PV_IS_LOCAL))) {
+		/* Process migrated */
+		VPROC_UNLOCK_FLAG(v, "rssi_rcopy_to_user");
+		goto out_bad;
+	}
+	p = PVP(v)->pvp_pproc;
+	get_task_struct(p);
+	VPROC_UNLOCK_FLAG(v, "rssi_rcopy_to_user");
+
+	/* Caller responsible for range check */
+	copied = access_process_vm(p, to, data, data_len, 1);
+	*n = data_len - copied;
+	if (*n != 0)
+		*rerror = -EFAULT;
+	else
+		*rerror = 0;
+
+	put_task_struct(p);
+#ifdef VPROC_RELEASE__REFCNT_RACE_FIX
+	VPROC_RELE(v, "rssi_rcopy_to_user");
+#endif
+	return 0;
+
+out_bad:
+	*rerror = -ESRCH;
+	*n = data_len;
+#else /* TASK_HOLD_VPROC */
 	if (v != NULL) {
 		p = PVP(v)->pvp_pproc;
-#ifdef TASK_HOLD_VPROC
-		SSI_ASSERT(PVP(v)->pvp_flag & PV_IS_LOCAL);
-#else
 		SSI_ASSERT(p != NULL);
-#endif
 	}
 	else
 		p = NULL;
@@ -176,6 +256,7 @@
 	if (v)
 		VPROC_RELE(v, "rssi_rcopy_to_user");
 #endif
+#endif /* !TASK_HOLD_VPROC */
 
 	return 0;
 }
@@ -191,13 +272,51 @@
 	SSI_ASSERT(v != NULL);
 	SSI_ASSERT(*data_len > 0);
 	SSI_ASSERT(*data_len <= ICS_MAX_OOL_DATA_SIZE);
+
+#ifdef TASK_HOLD_VPROC
+	if (unlikely(v == NULL))
+		goto out_bad;
+
+	VPROC_LOCK_FLAG(v, "rssi_rcopy_strncpy_from_user");
+
+	if (unlikely(!(PVP(v)->pvp_flag & PV_IS_LOCAL))) {
+		VPROC_UNLOCK_FLAG(v, "rssi_rcopy_strncpy_from_user");
+		/* Process migrated */
+		goto out_bad;
+	}
+	p = PVP(v)->pvp_pproc;
+	get_task_struct(p);
+	VPROC_UNLOCK_FLAG(v, "rssi_rcopy_strncpy_from_user");
+
+	tmpn = *data_len;
+	smp_mb(); /* ensure tmpn value is visible */
+
+	*rerror = ssi_rcopy_strnlen_task(p, from, &tmpn);
+	if (*rerror >= 0) {
+		if (tmpn < *data_len)
+			*data_len = tmpn ;
+		(void)rssi_rcopy_from_user(to_node, rerror, pid,
+					   from, data, data_len);
+	} else
+		*data_len = 0;
+
+	put_task_struct(p);
+#ifdef VPROC_RELEASE__REFCNT_RACE_FIX
+	VPROC_RELE(v, "rssi_rcopy_strncpy_from_user");
+#endif
+	return 0;
+
+out_bad:
+#ifdef VPROC_RELEASE__REFCNT_RACE_FIX
+	if (v)
+		VPROC_RELE(v, "rssi_rcopy_strncpy_from_user");
+#endif
+	*rerror = -ESRCH;
+	*data_len = 0;
+#else /* TASK_HOLD_VPROC */
 	if (v != NULL) {
 		p = PVP(v)->pvp_pproc;
-#ifdef TASK_HOLD_VPROC
-		SSI_ASSERT(PVP(v)->pvp_flag & PV_IS_LOCAL);
-#else
 		SSI_ASSERT(p != NULL);
-#endif
 	}
 	else
 		p = NULL;
@@ -219,6 +338,7 @@
 	if (v)
 		VPROC_RELE(v, "rssi_rcopy_strncpy_from_user");
 #endif
+#endif /* !TASK_HOLD_VPROC */
 
 	return 0;
 }
@@ -232,13 +352,40 @@
 	SSI_ASSERT(v != NULL);
 	SSI_ASSERT(*n > 0);
 	SSI_ASSERT(*n <= ICS_MAX_OOL_DATA_SIZE);
+
+#ifdef TASK_HOLD_VPROC
+	if (unlikely(v == NULL))
+		goto out_bad;
+
+	VPROC_LOCK_FLAG(v, "rssi_rcopy_strnlen_user");
+
+	if (unlikely(!(PVP(v)->pvp_flag & PV_IS_LOCAL))) {
+		VPROC_UNLOCK_FLAG(v, "rssi_rcopy_strnlen_user");
+		/* Process migrated */
+		goto out_bad;
+	}
+	p = PVP(v)->pvp_pproc;
+	get_task_struct(p);
+	VPROC_UNLOCK_FLAG(v, "rssi_rcopy_strnlen_user");
+
+	*rerror = ssi_rcopy_strnlen_task(p, from, n);
+	put_task_struct(p);
+#ifdef VPROC_RELEASE__REFCNT_RACE_FIX
+	VPROC_RELE(v, "rssi_rcopy_strnlen_user");
+#endif
+	return 0;
+
+out_bad:
+#ifdef VPROC_RELEASE__REFCNT_RACE_FIX
+	if (v)
+		VPROC_RELE(v, "rssi_rcopy_strnlen_user");
+#endif
+	*rerror = -ESRCH;
+	(*n)++;
+#else /* TASK_HOLD_VPROC */
 	if (v != NULL) {
 		p = PVP(v)->pvp_pproc;
-#ifdef TASK_HOLD_VPROC
-		SSI_ASSERT(PVP(v)->pvp_flag & PV_IS_LOCAL);
-#else
 		SSI_ASSERT(p != NULL);
-#endif
 	}
 	else
 		p = NULL;
@@ -252,6 +399,7 @@
 	if (v)
 		VPROC_RELE(v, "rssi_rcopy_strnlen_user");
 #endif
+#endif /* !TASK_HOLD_VPROC */
 
 	return 0;
 }
@@ -268,6 +416,55 @@
 	SSI_ASSERT(v != NULL);
 	SSI_ASSERT(*n > 0);
 	SSI_ASSERT(*n <= ICS_MAX_OOL_DATA_SIZE);
+
+#ifdef TASK_HOLD_VPROC
+	if (unlikely(v == NULL)) {
+		*rerror = -ESRCH;
+		goto out;
+	}
+
+	VPROC_LOCK_FLAG(v, "rssi_rcopy_clear_user");
+
+	if (unlikely(!(PVP(v)->pvp_flag & PV_IS_LOCAL))) {
+		VPROC_UNLOCK_FLAG(v, "rssi_rcopy_clear_user");
+		/* Process migrated */
+		*rerror = -ESRCH;
+		goto out;
+	}
+	p = PVP(v)->pvp_pproc;
+	get_task_struct(p);
+	VPROC_UNLOCK_FLAG(v, "rssi_rcopy_clear_user");
+
+	cbuf = (char *)get_zeroed_page(GFP_USER);
+	if (cbuf != NULL) {
+		*rerror = 0;
+		copy = PAGE_SIZE;
+		while (*n > 0) {
+			if (*n < PAGE_SIZE)
+				copy = *n;
+
+			copied = access_process_vm(p, to, cbuf, copy, 1);
+			if (copied > 0) {
+				*n -= copied;
+				to += copied;
+			}
+			if (copied != copy) {
+				*rerror = -EFAULT;
+				break;
+			}
+		}
+		free_page((u_long)cbuf);
+	}
+	else
+		*rerror = -ENOMEM;
+
+	put_task_struct(p);
+out:
+#ifdef VPROC_RELEASE__REFCNT_RACE_FIX
+	if (v)
+		VPROC_RELE(v, "rssi_rcopy_clear_user");
+#endif
+#else /* TASK_HOLD_VPROC */
 	if (v != NULL) {
 		p = PVP(v)->pvp_pproc;
 #ifdef TASK_HOLD_VPROC
@@ -307,6 +504,7 @@
 	if (v)
 		VPROC_RELE(v, "rssi_rcopy_clear_user");
 #endif
+#endif /* !TASK_HOLD_VPROC */
 
 	return 0;
 }
@@ -359,6 +557,9 @@
 			break;
 		}
 	}
+
+	rmb(); /* control dependency */
+
 	/* Zero remaining buffer. */
 	if (*n > 0)
 		memset(t, 0, *n);
@@ -459,6 +660,7 @@
 			data_len = ICS_MAX_OOL_DATA_SIZE;
 		else
 			data_len = nbytes;
+
 		saved_len = data_len;
 		for (;;) {
 			if (to_node == this_node ||
@@ -494,7 +696,8 @@
 		if (data_len != saved_len)
 			break;
 	}
-	if (*n > 0 && t[-1] == '\0')
+	rmb(); /* control dependency */
+	if (*n > 0 && *(t-1) == '\0')
 		(*n)--;
 
 	return error;


------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.