## Automatically generated incremental diff
## From:   linux-2.4.18-rc1
## To:     linux-2.4.18-rc2
## Robot:  $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $

diff -urN linux-2.4.18-rc1/Makefile linux/Makefile
--- linux-2.4.18-rc1/Makefile	Mon Feb 18 13:25:21 2002
+++ linux/Makefile	Mon Feb 18 13:25:29 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 18
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.18-rc1/arch/mips64/kernel/linux32.c linux/arch/mips64/kernel/linux32.c
--- linux-2.4.18-rc1/arch/mips64/kernel/linux32.c	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips64/kernel/linux32.c	Mon Feb 18 13:25:29 2002
@@ -1066,7 +1066,7 @@
 		goto out;
 	ret = read(file, buf, count, &pos);
 	if (ret > 0)
-		inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS);
+		dnotify_parent(file->f_dentry, DN_ACCESS);
 out:
 	fput(file);
 bad_file:
@@ -1098,7 +1098,7 @@
 
 	ret = write(file, buf, count, &pos);
 	if (ret > 0)
-		inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_MODIFY);
+		dnotify_parent(file->f_dentry, DN_MODIFY);
 out:
 	fput(file);
 bad_file:
diff -urN linux-2.4.18-rc1/fs/attr.c linux/fs/attr.c
--- linux-2.4.18-rc1/fs/attr.c	Thu Oct 11 09:43:30 2001
+++ linux/fs/attr.c	Mon Feb 18 13:25:34 2002
@@ -144,7 +144,7 @@
 	if (!error) {
 		unsigned long dn_mask = setattr_mask(ia_valid);
 		if (dn_mask)
-			inode_dir_notify(dentry->d_parent->d_inode, dn_mask);
+			dnotify_parent(dentry, dn_mask);
 	}
 	return error;
 }
diff -urN linux-2.4.18-rc1/fs/read_write.c linux/fs/read_write.c
--- linux-2.4.18-rc1/fs/read_write.c	Sun Aug  5 13:12:41 2001
+++ linux/fs/read_write.c	Mon Feb 18 13:25:35 2002
@@ -163,8 +163,7 @@
 			}
 		}
 		if (ret > 0)
-			inode_dir_notify(file->f_dentry->d_parent->d_inode,
-				DN_ACCESS);
+			dnotify_parent(file->f_dentry, DN_ACCESS);
 		fput(file);
 	}
 	return ret;
@@ -190,8 +189,7 @@
 			}
 		}
 		if (ret > 0)
-			inode_dir_notify(file->f_dentry->d_parent->d_inode,
-				DN_MODIFY);
+			dnotify_parent(file->f_dentry, DN_MODIFY);
 		fput(file);
 	}
 	return ret;
@@ -295,7 +293,7 @@
 out_nofree:
 	/* VERIFY_WRITE actually means a read, as we write to user space */
 	if ((ret + (type == VERIFY_WRITE)) > 0)
-		inode_dir_notify(file->f_dentry->d_parent->d_inode,
+		dnotify_parent(file->f_dentry,
 			(type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
 	return ret;
 }
@@ -368,7 +366,7 @@
 		goto out;
 	ret = read(file, buf, count, &pos);
 	if (ret > 0)
-		inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS);
+		dnotify_parent(file->f_dentry, DN_ACCESS);
 out:
 	fput(file);
 bad_file:
@@ -400,7 +398,7 @@
 
 	ret = write(file, buf, count, &pos);
 	if (ret > 0)
-		inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_MODIFY);
+		dnotify_parent(file->f_dentry, DN_MODIFY);
 out:
 	fput(file);
 bad_file:
diff -urN linux-2.4.18-rc1/include/linux/dnotify.h linux/include/linux/dnotify.h
--- linux-2.4.18-rc1/include/linux/dnotify.h	Fri Sep 22 14:21:22 2000
+++ linux/include/linux/dnotify.h	Mon Feb 18 13:25:35 2002
@@ -23,3 +23,21 @@
 	if ((inode)->i_dnotify_mask & (event))
 		__inode_dir_notify(inode, event);
 }
+
+/*
+ * This is hopelessly wrong, but unfixable without API changes.  At
+ * least it doesn't oops the kernel...
+ */
+static inline void dnotify_parent(struct dentry *dentry, unsigned long event)
+{
+	struct dentry *parent;
+	spin_lock(&dcache_lock);
+	parent = dentry->d_parent;
+	if (parent->d_inode->i_dnotify_mask & event) {
+		dget(parent);
+		spin_unlock(&dcache_lock);
+		__inode_dir_notify(parent->d_inode, event);
+		dput(parent);
+	} else
+		spin_unlock(&dcache_lock);
+}
diff -urN linux-2.4.18-rc1/kernel/fork.c linux/kernel/fork.c
--- linux-2.4.18-rc1/kernel/fork.c	Mon Feb 18 13:25:26 2002
+++ linux/kernel/fork.c	Mon Feb 18 13:25:35 2002
@@ -85,6 +85,7 @@
 {
 	static int next_safe = PID_MAX;
 	struct task_struct *p;
+	int pid;
 
 	if (flags & CLONE_PID)
 		return current->pid;
@@ -120,9 +121,10 @@
 		}
 		read_unlock(&tasklist_lock);
 	}
+	pid = last_pid;
 	spin_unlock(&lastpid_lock);
 
-	return last_pid;
+	return pid;
 }
 
 static inline int dup_mmap(struct mm_struct * mm)
diff -urN linux-2.4.18-rc1/mm/memory.c linux/mm/memory.c
--- linux-2.4.18-rc1/mm/memory.c	Fri Dec 21 09:42:05 2001
+++ linux/mm/memory.c	Mon Feb 18 13:25:35 2002
@@ -442,6 +442,13 @@
 	return page;
 }
 
+/*
+ * Please read Documentation/cachetlb.txt before using this function,
+ * accessing foreign memory spaces can cause cache coherency problems.
+ *
+ * Accessing a VM_IO area is even more dangerous, therefore the function
+ * fails if pages is != NULL and a VM_IO area is found.
+ */
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas)
 {
@@ -453,6 +460,7 @@
 		vma = find_extend_vma(mm, start);
 
 		if ( !vma ||
+		    (pages && vma->vm_flags & VM_IO) ||
 		    (!force &&
 		     	((write && (!(vma->vm_flags & VM_WRITE))) ||
 		    	 (!write && (!(vma->vm_flags & VM_READ))) ) )) {
@@ -486,8 +494,9 @@
 				/* FIXME: call the correct function,
 				 * depending on the type of the found page
 				 */
-				if (pages[i])
-					page_cache_get(pages[i]);
+				if (!pages[i])
+					goto bad_page;
+				page_cache_get(pages[i]);
 			}
 			if (vmas)
 				vmas[i] = vma;
@@ -497,7 +506,19 @@
 		} while(len && start < vma->vm_end);
 		spin_unlock(&mm->page_table_lock);
 	} while(len);
+out:
 	return i;
+
+	/*
+	 * We found an invalid page in the VMA.  Release all we have
+	 * so far and fail.
+	 */
+bad_page:
+	spin_unlock(&mm->page_table_lock);
+	while (i--)
+		page_cache_release(pages[i]);
+	i = -EFAULT;
+	goto out;
 }
 
 /*
diff -urN linux-2.4.18-rc1/mm/shmem.c linux/mm/shmem.c
--- linux-2.4.18-rc1/mm/shmem.c	Fri Dec 21 09:42:05 2001
+++ linux/mm/shmem.c	Mon Feb 18 13:25:35 2002
@@ -752,6 +752,11 @@
 	long		status;
 	int		err;
 
+	if ((ssize_t) count < 0)
+		return -EINVAL;
+
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;
 
 	down(&inode->i_sem);
 
