patch-2.3.7 linux/fs/ext2/file.c

Next file: linux/fs/ext2/fsync.c
Previous file: linux/fs/ext2/dir.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.6/linux/fs/ext2/file.c linux/fs/ext2/file.c
@@ -30,15 +30,15 @@
 #include <linux/locks.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
+#include <linux/smp_lock.h>
 
 #define	NBUF	32
 
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
+static int ext2_writepage (struct file * file, struct page * page);
 static long long ext2_file_lseek(struct file *, long long, int);
-static ssize_t ext2_file_write (struct file *, const char *, size_t, loff_t *);
-static int ext2_release_file (struct inode *, struct file *);
 #if BITS_PER_LONG < 64
 static int ext2_open_file (struct inode *, struct file *);
 
@@ -57,51 +57,6 @@
 
 #endif
 
-/*
- * We have mostly NULL's here: the current defaults are ok for
- * the ext2 filesystem.
- */
-static struct file_operations ext2_file_operations = {
-	ext2_file_lseek,	/* lseek */
-	generic_file_read,	/* read */
-	ext2_file_write,	/* write */
-	NULL,			/* readdir - bad */
-	NULL,			/* poll - default */
-	ext2_ioctl,		/* ioctl */
-	generic_file_mmap,	/* mmap */
-#if BITS_PER_LONG == 64	
-	NULL,			/* no special open is needed */
-#else
-	ext2_open_file,
-#endif
-	NULL,			/* flush */
-	ext2_release_file,	/* release */
-	ext2_sync_file,		/* fsync */
-	NULL,			/* fasync */
-	NULL,			/* check_media_change */
-	NULL			/* revalidate */
-};
-
-struct inode_operations ext2_file_inode_operations = {
-	&ext2_file_operations,/* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
-	NULL,			/* writepage */
-	ext2_bmap,		/* bmap */
-	ext2_truncate,		/* truncate */
-	ext2_permission,	/* permission */
-	NULL			/* smap */
-};
 
 /*
  * Make sure the offset never goes beyond the 32-bit mark..
@@ -151,164 +106,30 @@
 	}
 }
 
-static ssize_t ext2_file_write (struct file * filp, const char * buf,
-				size_t count, loff_t *ppos)
+static int ext2_writepage (struct file * file, struct page * page)
 {
-	struct inode * inode = filp->f_dentry->d_inode;
-	off_t pos;
-	long block;
-	int offset;
-	int written, c;
-	struct buffer_head * bh, *bufferlist[NBUF];
-	struct super_block * sb;
-	int err;
-	int i,buffercount,write_error;
-
-	/* POSIX: mtime/ctime may not change for 0 count */
-	if (!count)
-		return 0;
-	write_error = buffercount = 0;
-	if (!inode) {
-		printk("ext2_file_write: inode = NULL\n");
-		return -EINVAL;
-	}
-	sb = inode->i_sb;
-	if (sb->s_flags & MS_RDONLY)
-		/*
-		 * This fs has been automatically remounted ro because of errors
-		 */
-		return -ENOSPC;
-
-	if (!S_ISREG(inode->i_mode)) {
-		ext2_warning (sb, "ext2_file_write", "mode = %07o",
-			      inode->i_mode);
-		return -EINVAL;
-	}
-	remove_suid(inode);
-
-	if (filp->f_flags & O_APPEND)
-		pos = inode->i_size;
-	else {
-		pos = *ppos;
-		if (pos != *ppos)
-			return -EINVAL;
-#if BITS_PER_LONG >= 64
-		if (pos > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)])
-			return -EINVAL;
-#endif
-	}
+	return block_write_full_page(file, page, ext2_getblk_block);
+}
 
-	/* Check for overflow.. */
-#if BITS_PER_LONG < 64
-	if (pos > (__u32) (pos + count)) {
-		count = ~pos; /* == 0xFFFFFFFF - pos */
-		if (!count)
-			return -EFBIG;
-	}
-#else
-	{
-		off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)];
+static long ext2_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+{
+	return block_write_partial_page(file, page, offset, bytes, buf, ext2_getblk_block);
+}
 
-		if (pos + count > max) {
-			count = max - pos;
-			if (!count)
-				return -EFBIG;
-		}
-		if (((pos + count) >> 32) && 
-		    !(sb->u.ext2_sb.s_es->s_feature_ro_compat &
-		      cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) {
-			/* If this is the first large file created, add a flag
-			   to the superblock */
-			sb->u.ext2_sb.s_es->s_feature_ro_compat |=
-				cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
-			mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
-		}
+/*
+ * Write to a file (through the page cache).
+ */
+static ssize_t
+ext2_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	ssize_t retval = generic_file_write(file, buf, count, ppos, ext2_write_one_page);
+	if (retval > 0) {
+		struct inode *inode = file->f_dentry->d_inode;
+		remove_suid(inode);
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		mark_inode_dirty(inode);
 	}
-#endif
-
-	/*
-	 * If a file has been opened in synchronous mode, we have to ensure
-	 * that meta-data will also be written synchronously.  Thus, we
-	 * set the i_osync field.  This field is tested by the allocation
-	 * routines.
-	 */
-	if (filp->f_flags & O_SYNC)
-		inode->u.ext2_i.i_osync++;
-	block = pos >> EXT2_BLOCK_SIZE_BITS(sb);
-	offset = pos & (sb->s_blocksize - 1);
-	c = sb->s_blocksize - offset;
-	written = 0;
-	do {
-		bh = ext2_getblk (inode, block, 1, &err);
-		if (!bh) {
-			if (!written)
-				written = err;
-			break;
-		}
-		if (c > count)
-			c = count;
-		if (c != sb->s_blocksize && !buffer_uptodate(bh)) {
-			ll_rw_block (READ, 1, &bh);
-			wait_on_buffer (bh);
-			if (!buffer_uptodate(bh)) {
-				brelse (bh);
-				if (!written)
-					written = -EIO;
-				break;
-			}
-		}
-		c -= copy_from_user (bh->b_data + offset, buf, c);
-		if (!c) {
-			brelse(bh);
-			if (!written)
-				written = -EFAULT;
-			break;
-		}
-		update_vm_cache(inode, pos, bh->b_data + offset, c);
-		pos += c;
-		written += c;
-		buf += c;
-		count -= c;
-		mark_buffer_uptodate(bh, 1);
-		mark_buffer_dirty(bh, 0);
-
-		if (filp->f_flags & O_SYNC)
-			bufferlist[buffercount++] = bh;
-		else
-			brelse(bh);
-		if (buffercount == NBUF){
-			ll_rw_block(WRITE, buffercount, bufferlist);
-			for(i=0; i<buffercount; i++){
-				wait_on_buffer(bufferlist[i]);
-				if (!buffer_uptodate(bufferlist[i]))
-					write_error=1;
-				brelse(bufferlist[i]);
-			}
-			buffercount=0;
-		}
-		if(write_error)
-			break;
-		block++;
-		offset = 0;
-		c = sb->s_blocksize;
-	} while (count);
-	if ( buffercount ){
-		ll_rw_block(WRITE, buffercount, bufferlist);
-		for(i=0; i<buffercount; i++){
-			wait_on_buffer(bufferlist[i]);
-			if (!buffer_uptodate(bufferlist[i]))
-				write_error=1;
-			brelse(bufferlist[i]);
-		}
-	}		
-	if (pos > inode->i_size)
-		inode->i_size = pos;
-	if (filp->f_flags & O_SYNC)
-		inode->u.ext2_i.i_osync--;
-	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-	*ppos = pos;
-	mark_inode_dirty(inode);
-	return written;
+	return retval;
 }
 
 /*
@@ -335,3 +156,51 @@
 	return 0;
 }
 #endif
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the ext2 filesystem.
+ */
+static struct file_operations ext2_file_operations = {
+	ext2_file_lseek,	/* lseek */
+	generic_file_read,	/* read */
+	ext2_file_write,	/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* poll - default */
+	ext2_ioctl,		/* ioctl */
+	generic_file_mmap,	/* mmap */
+#if BITS_PER_LONG == 64	
+	NULL,			/* no special open is needed */
+#else
+	ext2_open_file,
+#endif
+	NULL,			/* flush */
+	ext2_release_file,	/* release */
+	ext2_sync_file,		/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL			/* revalidate */
+};
+
+struct inode_operations ext2_file_inode_operations = {
+	&ext2_file_operations,/* default file operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	ext2_bmap,		/* bmap */
+	block_read_full_page,	/* readpage */
+	ext2_writepage,		/* writepage */
+	block_flushpage,	/* flushpage */
+	ext2_truncate,		/* truncate */
+	ext2_permission,	/* permission */
+	NULL,			/* smap */
+	NULL,			/* revalidate */
+};

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)