

Patch from: Oleg Drokin <green@namesys.com>

It moves all the arg checking code from the start of generic_file_aio_write()
into a standalone function, so other filesystems can avoid having to
cut-n-paste them.

I made the new function `static inline', because nothing is actually using it
yet.  Later, we can remove the `static', so it is still inlined for the
current filesystems.


 filemap.c |  172 ++++++++++++++++++++++++++++++++------------------------------
 1 files changed, 90 insertions(+), 82 deletions(-)

diff -puN mm/filemap.c~generic_write_checks mm/filemap.c
--- 25/mm/filemap.c~generic_write_checks	2003-02-13 22:08:50.000000000 -0800
+++ 25-akpm/mm/filemap.c	2003-02-13 23:01:40.000000000 -0800
@@ -1486,6 +1486,90 @@ filemap_set_next_iovec(const struct iove
 	*basep = base;
 }
 
+/*
+ * Performs necessary checks before doing a write
+ *
+ * Can adjust writing position aor amount of bytes to write.
+ * Returns appropriate error code that caller should return or
+ * zero in case that write should be allowed.
+ */
+static int generic_write_checks(struct inode *inode, struct file *file,
+				loff_t *pos, size_t *count, int isblk)
+{
+	unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+
+        if (unlikely(*pos < 0))
+                return -EINVAL;
+
+        if (unlikely(file->f_error)) {
+                int err = file->f_error;
+                file->f_error = 0;
+                return err;
+        }
+
+	if (!isblk) {
+		/* FIXME: this is for backwards compatibility with 2.4 */
+		if (file->f_flags & O_APPEND)
+                        *pos = inode->i_size;
+
+		if (limit != RLIM_INFINITY) {
+			if (*pos >= limit) {
+				send_sig(SIGXFSZ, current, 0);
+				return -EFBIG;
+			}
+			if (*pos > 0xFFFFFFFFULL || *count > limit-(u32)*pos) {
+				/* send_sig(SIGXFSZ, current, 0); */
+				*count = limit - (u32)*pos;
+			}
+		}
+	}
+
+	/*
+	 * LFS rule
+	 */
+	if (unlikely(*pos + *count > MAX_NON_LFS &&
+				!(file->f_flags & O_LARGEFILE))) {
+		if (*pos >= MAX_NON_LFS) {
+			send_sig(SIGXFSZ, current, 0);
+			return -EFBIG;
+		}
+		if (*count > MAX_NON_LFS - (u32)*pos) {
+			/* send_sig(SIGXFSZ, current, 0); */
+			*count = MAX_NON_LFS - (u32)*pos;
+		}
+	}
+
+	/*
+	 * Are we about to exceed the fs block limit ?
+	 *
+	 * If we have written data it becomes a short write.  If we have
+	 * exceeded without writing data we send a signal and return EFBIG.
+	 * Linus frestrict idea will clean these up nicely..
+	 */
+	if (likely(!isblk)) {
+		if (unlikely(*pos >= inode->i_sb->s_maxbytes)) {
+			if (*count || *pos > inode->i_sb->s_maxbytes) {
+				send_sig(SIGXFSZ, current, 0);
+				return -EFBIG;
+			}
+			/* zero-length writes at ->s_maxbytes are OK */
+		}
+
+		if (unlikely(*pos + *count > inode->i_sb->s_maxbytes))
+			*count = inode->i_sb->s_maxbytes - *pos;
+	} else {
+		if (bdev_read_only(inode->i_bdev))
+			return -EPERM;
+		if (*pos >= inode->i_size) {
+			if (*count || *pos > inode->i_size)
+				return -ENOSPC;
+		}
+
+		if (*pos + *count > inode->i_size)
+			*count = inode->i_size - *pos;
+	}
+	return 0;
+}
 
 /*
  * Write to a file through the page cache. 
@@ -1506,12 +1590,11 @@ generic_file_aio_write_nolock(struct kio
 	size_t ocount;		/* original count */
 	size_t count;		/* after file limit checks */
 	struct inode 	*inode = mapping->host;
-	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-	const int	isblk = S_ISBLK(inode->i_mode);
 	long		status = 0;
 	loff_t		pos;
 	struct page	*page;
 	struct page	*cached_page = NULL;
+	const int	isblk = S_ISBLK(inode->i_mode);
 	ssize_t		written;
 	ssize_t		err;
 	size_t		bytes;
@@ -1540,95 +1623,20 @@ generic_file_aio_write_nolock(struct kio
 		ocount -= iv->iov_len;	/* This segment is no good */
 		break;
 	}
-	count = ocount;
 
+	count = ocount;
 	pos = *ppos;
-	if (unlikely(pos < 0))
-		return -EINVAL;
+	pagevec_init(&lru_pvec, 0);
 
 	/* We can write back this queue in page reclaim */
 	current->backing_dev_info = mapping->backing_dev_info;
-
-	pagevec_init(&lru_pvec, 0);
-
-	if (unlikely(file->f_error)) {
-		err = file->f_error;
-		file->f_error = 0;
-		goto out;
-	}
-
 	written = 0;
 
-	if (!isblk) {
-		/* FIXME: this is for backwards compatibility with 2.4 */
-		if (file->f_flags & O_APPEND)
-			pos = inode->i_size;
-
-		if (limit != RLIM_INFINITY) {
-			if (pos >= limit) {
-				send_sig(SIGXFSZ, current, 0);
-				err = -EFBIG;
-				goto out;
-			}
-			if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) {
-				/* send_sig(SIGXFSZ, current, 0); */
-				count = limit - (u32)pos;
-			}
-		}
-	}
-
-	/*
-	 * LFS rule
-	 */
-	if (unlikely(pos + count > MAX_NON_LFS &&
-				!(file->f_flags & O_LARGEFILE))) {
-		if (pos >= MAX_NON_LFS) {
-			send_sig(SIGXFSZ, current, 0);
-			err = -EFBIG;
-			goto out;
-		}
-		if (count > MAX_NON_LFS - (u32)pos) {
-			/* send_sig(SIGXFSZ, current, 0); */
-			count = MAX_NON_LFS - (u32)pos;
-		}
-	}
-
-	/*
-	 * Are we about to exceed the fs block limit ?
-	 *
-	 * If we have written data it becomes a short write.  If we have
-	 * exceeded without writing data we send a signal and return EFBIG.
-	 * Linus frestrict idea will clean these up nicely..
-	 */
-	if (likely(!isblk)) {
-		if (unlikely(pos >= inode->i_sb->s_maxbytes)) {
-			if (count || pos > inode->i_sb->s_maxbytes) {
-				send_sig(SIGXFSZ, current, 0);
-				err = -EFBIG;
-				goto out;
-			}
-			/* zero-length writes at ->s_maxbytes are OK */
-		}
-
-		if (unlikely(pos + count > inode->i_sb->s_maxbytes))
-			count = inode->i_sb->s_maxbytes - pos;
-	} else {
-		if (bdev_read_only(inode->i_bdev)) {
-			err = -EPERM;
-			goto out;
-		}
-		if (pos >= inode->i_size) {
-			if (count || pos > inode->i_size) {
-				err = -ENOSPC;
-				goto out;
-			}
-		}
+	err = generic_write_checks(inode, file, &pos, &count, isblk);
+	if (err)
+		goto out;
 
-		if (pos + count > inode->i_size)
-			count = inode->i_size - pos;
-	}
 
-	err = 0;
 	if (count == 0)
 		goto out;
 

_
