linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2.5.64 2/2] i_size atomic access
@ 2003-03-08  0:15 Daniel McNeil
  2003-03-08  0:30 ` Andrew Morton
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel McNeil @ 2003-03-08  0:15 UTC (permalink / raw)
  To: Andrea Arcangeli, Andrew Morton, Linux Kernel Mailing List
  Cc: Stephen Hemminger, Linus Torvalds

This adds i_seqcnt to inode structure and then uses i_size_read() and
i_size_write() to provide atomic access to i_size.  This is port
of Andrea Arcangeli i_size atomic access patch from 2.4.  This only
uses the generic read reader/writer consistent mechanism.

-- 
Daniel McNeil <daniel@osdl.org>

diff -urNp -X /home/daniel/dontdiff linux-2.5.64/drivers/block/loop.c
linux-2.5.64-isize/drivers/block/loop.c
--- linux-2.5.64/drivers/block/loop.c	Tue Mar  4 19:29:22 2003
+++ linux-2.5.64-isize/drivers/block/loop.c	Thu Mar  6 15:30:42 2003
@@ -153,8 +153,9 @@ struct loop_func_table *xfer_funcs[MAX_L
 
 static int figure_loop_size(struct loop_device *lo)
 {
-	loff_t size =
lo->lo_backing_file->f_dentry->d_inode->i_mapping->host->i_size;
+	loff_t size =
i_size_read(lo->lo_backing_file->f_dentry->d_inode->i_mapping->host);
 	sector_t x;
+	printk("mcneil tmp %Ld %x", size,
lo->lo_backing_file->f_dentry->d_inode->i_mapping->host);
 	/*
 	 * Unfortunately, if we want to do I/O on the device,
 	 * the number of 512-byte sectors has to fit into a sector_t.
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/attr.c
linux-2.5.64-isize/fs/attr.c
--- linux-2.5.64/fs/attr.c	Tue Mar  4 19:28:59 2003
+++ linux-2.5.64-isize/fs/attr.c	Thu Mar  6 15:30:42 2003
@@ -68,7 +68,7 @@ int inode_setattr(struct inode * inode, 
 	int error = 0;
 
 	if (ia_valid & ATTR_SIZE) {
-		if (attr->ia_size == inode->i_size) {
+		if (attr->ia_size == i_size_read(inode)) {
 			if (ia_valid == ATTR_SIZE)
 				goto out;	/* we can skip lock_kernel() */
 		} else {
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/binfmt_aout.c
linux-2.5.64-isize/fs/binfmt_aout.c
--- linux-2.5.64/fs/binfmt_aout.c	Tue Mar  4 19:29:02 2003
+++ linux-2.5.64-isize/fs/binfmt_aout.c	Thu Mar  6 15:30:42 2003
@@ -269,7 +269,7 @@ static int load_aout_binary(struct linux
 	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
 	     N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
 	    N_TRSIZE(ex) || N_DRSIZE(ex) ||
-	    bprm->file->f_dentry->d_inode->i_size <
ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+	    i_size_read(bprm->file->f_dentry->d_inode) <
ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 		return -ENOEXEC;
 	}
 
@@ -454,7 +454,7 @@ static int load_aout_library(struct file
 	/* We come in here for the regular a.out style of shared libraries */
 	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex)
||
 	    N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
-	    inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+	    i_size_read(inode) <
ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 		goto out;
 	}
 
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/block_dev.c
linux-2.5.64-isize/fs/block_dev.c
--- linux-2.5.64/fs/block_dev.c	Tue Mar  4 19:29:56 2003
+++ linux-2.5.64-isize/fs/block_dev.c	Thu Mar  6 15:30:42 2003
@@ -29,7 +29,7 @@
 static sector_t max_block(struct block_device *bdev)
 {
 	sector_t retval = ~((sector_t)0);
-	loff_t sz = bdev->bd_inode->i_size;
+	loff_t sz = i_size_read(bdev->bd_inode);
 
 	if (sz) {
 		unsigned int size = block_size(bdev);
@@ -156,7 +156,7 @@ static int blkdev_commit_write(struct fi
 static loff_t block_llseek(struct file *file, loff_t offset, int
origin)
 {
 	/* ewww */
-	loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size;
+	loff_t size = i_size_read(file->f_dentry->d_inode->i_bdev->bd_inode);
 	loff_t retval;
 
 	lock_kernel();
@@ -549,7 +549,7 @@ int __check_disk_change(dev_t dev)
 static void bd_set_size(struct block_device *bdev, loff_t size)
 {
 	unsigned bsize = bdev_hardsect_size(bdev);
-	bdev->bd_inode->i_size = size;
+	i_size_write(bdev->bd_inode, size);
 	while (bsize < PAGE_CACHE_SIZE) {
 		if (size & bsize)
 			break;
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/buffer.c
linux-2.5.64-isize/fs/buffer.c
--- linux-2.5.64/fs/buffer.c	Tue Mar  4 19:29:22 2003
+++ linux-2.5.64-isize/fs/buffer.c	Thu Mar  6 15:30:42 2003
@@ -1623,7 +1623,7 @@ static int __block_write_full_page(struc
 
 	BUG_ON(!PageLocked(page));
 
-	last_block = (inode->i_size - 1) >> inode->i_blkbits;
+	last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;
 
 	if (!page_has_buffers(page)) {
 		if (!PageUptodate(page))
@@ -1961,7 +1961,7 @@ int block_read_full_page(struct page *pa
 
 	blocks = PAGE_CACHE_SIZE >> inode->i_blkbits;
 	iblock = (sector_t)page->index << (PAGE_CACHE_SHIFT -
inode->i_blkbits);
-	lblock = (inode->i_size+blocksize-1) >> inode->i_blkbits;
+	lblock = (i_size_read(inode)+blocksize-1) >> inode->i_blkbits;
 	bh = head;
 	nr = 0;
 	i = 0;
@@ -2186,8 +2186,12 @@ int generic_commit_write(struct file *fi
 	struct inode *inode = page->mapping->host;
 	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
 	__block_commit_write(inode,page,from,to);
+	/*
+	 * No need to use i_size_read() here, the i_size
+	 * cannot change under us because we hold i_sem.
+	 */
 	if (pos > inode->i_size) {
-		inode->i_size = pos;
+		i_size_write(inode, pos);
 		mark_inode_dirty(inode);
 	}
 	return 0;
@@ -2339,7 +2343,7 @@ int nobh_commit_write(struct file *file,
 
 	set_page_dirty(page);
 	if (pos > inode->i_size) {
-		inode->i_size = pos;
+		i_size_write(inode, pos);
 		mark_inode_dirty(inode);
 	}
 	return 0;
@@ -2469,7 +2473,8 @@ int block_write_full_page(struct page *p
 			struct writeback_control *wbc)
 {
 	struct inode * const inode = page->mapping->host;
-	const unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	loff_t i_size = i_size_read(inode);
+	const unsigned long end_index = i_size >> PAGE_CACHE_SHIFT;
 	unsigned offset;
 	void *kaddr;
 
@@ -2478,7 +2483,7 @@ int block_write_full_page(struct page *p
 		return __block_write_full_page(inode, page, get_block, wbc);
 
 	/* Is the page fully outside i_size? (truncate in progress) */
-	offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+	offset = i_size & (PAGE_CACHE_SIZE-1);
 	if (page->index >= end_index+1 || !offset) {
 		/*
 		 * The page may have dirty, unmapped buffers.  For example,
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/ext3/inode.c
linux-2.5.64-isize/fs/ext3/inode.c
--- linux-2.5.64/fs/ext3/inode.c	Tue Mar  4 19:29:30 2003
+++ linux-2.5.64-isize/fs/ext3/inode.c	Thu Mar  6 15:30:42 2003
@@ -1158,7 +1158,7 @@ static int ext3_commit_write(struct file
 		if (!partial)
 			SetPageUptodate(page);
 		if (pos > inode->i_size)
-			inode->i_size = pos;
+			i_size_write(inode, pos);
 		EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
 	} else {
 		if (ext3_should_order_data(inode)) {
@@ -1473,7 +1473,7 @@ out_stop:
 			loff_t end = offset + ret;
 			if (end > inode->i_size) {
 				ei->i_disksize = end;
-				inode->i_size = end;
+				i_size_write(inode, end);
 				err = ext3_mark_inode_dirty(handle, inode);
 				if (!ret) 
 					ret = err;
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/inode.c
linux-2.5.64-isize/fs/inode.c
--- linux-2.5.64/fs/inode.c	Tue Mar  4 19:29:54 2003
+++ linux-2.5.64-isize/fs/inode.c	Thu Mar  6 15:30:42 2003
@@ -188,6 +188,7 @@ void inode_init_once(struct inode *inode
 	INIT_LIST_HEAD(&inode->i_data.i_mmap);
 	INIT_LIST_HEAD(&inode->i_data.i_mmap_shared);
 	spin_lock_init(&inode->i_lock);
+	i_size_ordered_init(inode);
 }
 
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long
flags)
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/ioctl.c
linux-2.5.64-isize/fs/ioctl.c
--- linux-2.5.64/fs/ioctl.c	Tue Mar  4 19:29:03 2003
+++ linux-2.5.64-isize/fs/ioctl.c	Thu Mar  6 15:30:42 2003
@@ -40,7 +40,7 @@ static int file_ioctl(struct file *filp,
 				return -EBADF;
 			return put_user(inode->i_sb->s_blocksize, (int *) arg);
 		case FIONREAD:
-			return put_user(inode->i_size - filp->f_pos, (int *) arg);
+			return put_user(i_size_read(inode) - filp->f_pos, (int *) arg);
 	}
 	if (filp->f_op && filp->f_op->ioctl)
 		return filp->f_op->ioctl(inode, filp, cmd, arg);
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/libfs.c
linux-2.5.64-isize/fs/libfs.c
--- linux-2.5.64/fs/libfs.c	Tue Mar  4 19:28:53 2003
+++ linux-2.5.64-isize/fs/libfs.c	Thu Mar  6 15:30:42 2003
@@ -327,8 +327,12 @@ int simple_commit_write(struct file *fil
 	struct inode *inode = page->mapping->host;
 	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
 
+	/*
+	 * No need to use i_size_read() here, the i_size
+	 * cannot change under us because we hold the i_sem.
+	 */
 	if (pos > inode->i_size)
-		inode->i_size = pos;
+		i_size_write(inode, pos);
 	set_page_dirty(page);
 	return 0;
 }
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/locks.c
linux-2.5.64-isize/fs/locks.c
--- linux-2.5.64/fs/locks.c	Tue Mar  4 19:29:51 2003
+++ linux-2.5.64-isize/fs/locks.c	Thu Mar  6 15:30:42 2003
@@ -292,7 +292,7 @@ static int flock_to_posix_lock(struct fi
 		start = filp->f_pos;
 		break;
 	case 2: /*SEEK_END*/
-		start = filp->f_dentry->d_inode->i_size;
+		start = i_size_read(filp->f_dentry->d_inode);
 		break;
 	default:
 		return -EINVAL;
@@ -342,7 +342,7 @@ static int flock64_to_posix_lock(struct 
 		start = filp->f_pos;
 		break;
 	case 2: /*SEEK_END*/
-		start = filp->f_dentry->d_inode->i_size;
+		start = i_size_read(filp->f_dentry->d_inode);
 		break;
 	default:
 		return -EINVAL;
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/mpage.c
linux-2.5.64-isize/fs/mpage.c
--- linux-2.5.64/fs/mpage.c	Tue Mar  4 19:29:03 2003
+++ linux-2.5.64-isize/fs/mpage.c	Thu Mar  6 15:30:42 2003
@@ -227,7 +227,7 @@ do_mpage_readpage(struct bio *bio, struc
 		goto confused;
 
 	block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);
-	last_block = (inode->i_size + blocksize - 1) >> blkbits;
+	last_block = (i_size_read(inode) + blocksize - 1) >> blkbits;
 
 	bh.b_page = page;
 	for (page_block = 0; page_block < blocks_per_page;
@@ -459,7 +459,7 @@ mpage_writepage(struct bio *bio, struct 
 	 */
 	BUG_ON(!PageUptodate(page));
 	block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);
-	last_block = (inode->i_size - 1) >> blkbits;
+	last_block = (i_size_read(inode) - 1) >> blkbits;
 	map_bh.b_page = page;
 	for (page_block = 0; page_block < blocks_per_page; ) {
 
@@ -489,9 +489,9 @@ mpage_writepage(struct bio *bio, struct 
 
 	first_unmapped = page_block;
 
-	end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
 	if (page->index >= end_index) {
-		unsigned offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
+		unsigned offset = i_size_read(inode) & (PAGE_CACHE_SIZE - 1);
 		char *kaddr;
 
 		if (page->index > end_index || !offset)
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/open.c
linux-2.5.64-isize/fs/open.c
--- linux-2.5.64/fs/open.c	Tue Mar  4 19:28:57 2003
+++ linux-2.5.64-isize/fs/open.c	Thu Mar  6 15:30:42 2003
@@ -908,7 +908,7 @@ asmlinkage long sys_vhangup(void)
  */
 int generic_file_open(struct inode * inode, struct file * filp)
 {
-	if (!(filp->f_flags & O_LARGEFILE) && inode->i_size > MAX_NON_LFS)
+	if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) >
MAX_NON_LFS)
 		return -EFBIG;
 	return 0;
 }
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/quota_v1.c
linux-2.5.64-isize/fs/quota_v1.c
--- linux-2.5.64/fs/quota_v1.c	Tue Mar  4 19:29:32 2003
+++ linux-2.5.64-isize/fs/quota_v1.c	Thu Mar  6 15:30:42 2003
@@ -128,12 +128,14 @@ static int v1_check_quota_file(struct su
 	mm_segment_t fs;
 	ssize_t size;
 	loff_t offset = 0;
+	loff_t isize;
 	static const uint quota_magics[] = V2_INITQMAGICS;
 
-	if (!inode->i_size)
+	isize = i_size_read(inode);
+	if (!isize)
 		return 0;
-	blocks = inode->i_size >> BLOCK_SIZE_BITS;
-	off = inode->i_size & (BLOCK_SIZE - 1);
+	blocks = isize >> BLOCK_SIZE_BITS;
+	off = isize & (BLOCK_SIZE - 1);
 	if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) %
sizeof(struct v1_disk_dqblk))
 		return 0;
 	/* Doublecheck whether we didn't get file with new format - with old
quotactl() this could happen */
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/stat.c
linux-2.5.64-isize/fs/stat.c
--- linux-2.5.64/fs/stat.c	Tue Mar  4 19:29:02 2003
+++ linux-2.5.64-isize/fs/stat.c	Thu Mar  6 15:30:42 2003
@@ -28,7 +28,7 @@ void generic_fillattr(struct inode *inod
 	stat->atime = inode->i_atime;
 	stat->mtime = inode->i_mtime;
 	stat->ctime = inode->i_ctime;
-	stat->size = inode->i_size;
+	stat->size = i_size_read(inode);
 	stat->blocks = inode->i_blocks;
 	stat->blksize = inode->i_blksize;
 }
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/include/linux/fs.h
linux-2.5.64-isize/include/linux/fs.h
--- linux-2.5.64/include/linux/fs.h	Tue Mar  4 19:29:03 2003
+++ linux-2.5.64-isize/include/linux/fs.h	Thu Mar  6 15:30:42 2003
@@ -353,6 +353,17 @@ struct block_device {
 	struct gendisk *	bd_disk;
 };
 
+/*
+ * Use sequence counter to get consistent i_size on 32-bit processors.
+ */
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+#include <linux/seqlock.h>
+#define __NEED_I_SIZE_ORDERED
+#define i_size_ordered_init(inode) seqcnt_init(&inode->i_size_seqcnt)
+#else
+#define i_size_ordered_init(inode) do { } while (0)
+#endif
+
 struct inode {
 	struct hlist_node	i_hash;
 	struct list_head	i_list;
@@ -402,7 +413,59 @@ struct inode {
 	union {
 		void		*generic_ip;
 	} u;
+#ifdef __NEED_I_SIZE_ORDERED
+	seqcnt_t		i_size_seqcnt;
+#endif
 };
+
+/*
+ * NOTE: in a 32bit arch with a preemptable kernel and
+ * an UP compile the i_size_read/write must be atomic
+ * with respect to the local cpu (unlike with preempt disabled),
+ * but they don't need to be atomic with respect to other cpus like in
+ * true SMP (so they need either to either locally disable irq around
+ * the read or for example on x86 they can be still implemented as a
+ * cmpxchg8b without the need of the lock prefix). For SMP compiles
+ * and 64bit archs it makes no difference if preempt is enabled or not.
+ */
+static inline loff_t i_size_read(struct inode * inode)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	loff_t i_size;
+	unsigned int seq;
+
+	do {
+		seq = read_seqcntbegin(&inode->i_size_seqcnt);
+		i_size = inode->i_size;
+	} while (read_seqcntretry(&inode->i_size_seqcnt, seq));
+	return i_size;
+#elif BITS_PER_LONG==32 && defined(CONFIG_PREMPT)
+	loff_t i_size;
+
+	prempt_disable();
+	i_size = inode->i_size;
+	prempt_enable();
+	return i_size;
+#else
+	return inode->i_size;
+#endif
+}
+
+
+static inline void i_size_write(struct inode * inode, loff_t i_size)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	write_seqcntbegin(&inode->i_size_seqcnt);
+	inode->i_size = i_size;
+	write_seqcntend(&inode->i_size_seqcnt);
+#elif BITS_PER_LONG==32 && defined(CONFIG_PREMPT)
+	prempt_disable();
+	inode->i_size = i_size;
+	prempt_enable();
+#else
+	inode->i_size = i_size;
+#endif
+}
 
 struct fown_struct {
 	rwlock_t lock;          /* protects pid, uid, euid fields */
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/ipc/shm.c
linux-2.5.64-isize/ipc/shm.c
--- linux-2.5.64/ipc/shm.c	Tue Mar  4 19:29:19 2003
+++ linux-2.5.64-isize/ipc/shm.c	Thu Mar  6 15:30:42 2003
@@ -691,7 +691,7 @@ asmlinkage long sys_shmat (int shmid, ch
 	}
 		
 	file = shp->shm_file;
-	size = file->f_dentry->d_inode->i_size;
+	size = i_size_read(file->f_dentry->d_inode);
 	shp->shm_nattch++;
 	shm_unlock(shp);
 
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/filemap.c
linux-2.5.64-isize/mm/filemap.c
--- linux-2.5.64/mm/filemap.c	Tue Mar  4 19:29:15 2003
+++ linux-2.5.64-isize/mm/filemap.c	Thu Mar  6 15:30:42 2003
@@ -543,14 +543,15 @@ void do_generic_mapping_read(struct addr
 	for (;;) {
 		struct page *page;
 		unsigned long end_index, nr, ret;
+		loff_t isize = i_size_read(inode);
 
-		end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+		end_index = isize >> PAGE_CACHE_SHIFT;
 			
 		if (index > end_index)
 			break;
 		nr = PAGE_CACHE_SIZE;
 		if (index == end_index) {
-			nr = inode->i_size & ~PAGE_CACHE_MASK;
+			nr = isize & ~PAGE_CACHE_MASK;
 			if (nr <= offset)
 				break;
 		}
@@ -751,7 +752,7 @@ __generic_file_aio_read(struct kiocb *io
 		retval = 0;
 		if (!count)
 			goto out; /* skip atime */
-		size = inode->i_size;
+		size = i_size_read(inode);
 		if (pos < size) {
 			retval = generic_file_direct_IO(READ, iocb,
 						iov, pos, nr_segs);
@@ -940,7 +941,7 @@ retry_all:
 	 * An external ptracer can access pages that normally aren't
 	 * accessible..
 	 */
-	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	if ((pgoff >= size) && (area->vm_mm == current->mm))
 		return NULL;
 
@@ -1208,7 +1209,7 @@ static int filemap_populate(struct vm_ar
 	int err;
 
 repeat:
-	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	if (pgoff + (len >> PAGE_CACHE_SHIFT) > size)
 		return -EINVAL;
 
@@ -1497,7 +1498,7 @@ inline int generic_write_checks(struct i
 	if (!isblk) {
 		/* FIXME: this is for backwards compatibility with 2.4 */
 		if (file->f_flags & O_APPEND)
-                        *pos = inode->i_size;
+                        *pos = i_size_read(inode);
 
 		if (limit != RLIM_INFINITY) {
 			if (*pos >= limit) {
@@ -1545,15 +1546,17 @@ inline int generic_write_checks(struct i
 		if (unlikely(*pos + *count > inode->i_sb->s_maxbytes))
 			*count = inode->i_sb->s_maxbytes - *pos;
 	} else {
+		loff_t isize;
 		if (bdev_read_only(inode->i_bdev))
 			return -EPERM;
-		if (*pos >= inode->i_size) {
-			if (*count || *pos > inode->i_size)
+		isize = i_size_read(inode);
+		if (*pos >= isize) {
+			if (*count || *pos > isize)
 				return -ENOSPC;
 		}
 
-		if (*pos + *count > inode->i_size)
-			*count = inode->i_size - *pos;
+		if (*pos + *count > isize)
+			*count = isize - *pos;
 	}
 	return 0;
 }
@@ -1640,8 +1643,8 @@ generic_file_aio_write_nolock(struct kio
 					iov, pos, nr_segs);
 		if (written > 0) {
 			loff_t end = pos + written;
-			if (end > inode->i_size && !isblk) {
-				inode->i_size = end;
+			if (end > i_size_read(inode) && !isblk) {
+				i_size_write(inode,  end);
 				mark_inode_dirty(inode);
 			}
 			*ppos = end;
@@ -1685,14 +1688,15 @@ generic_file_aio_write_nolock(struct kio
 
 		status = a_ops->prepare_write(file, page, offset, offset+bytes);
 		if (unlikely(status)) {
+			loff_t isize = i_size_read(inode);
 			/*
 			 * prepare_write() may have instantiated a few blocks
 			 * outside i_size.  Trim these off again.
 			 */
 			unlock_page(page);
 			page_cache_release(page);
-			if (pos + bytes > inode->i_size)
-				vmtruncate(inode, inode->i_size);
+			if (pos + bytes > isize)
+				vmtruncate(inode, isize);
 			break;
 		}
 		if (likely(nr_segs == 1))
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/memory.c
linux-2.5.64-isize/mm/memory.c
--- linux-2.5.64/mm/memory.c	Tue Mar  4 19:29:18 2003
+++ linux-2.5.64-isize/mm/memory.c	Thu Mar  6 15:30:42 2003
@@ -1055,7 +1055,7 @@ int vmtruncate(struct inode * inode, lof
 
 	if (inode->i_size < offset)
 		goto do_expand;
-	inode->i_size = offset;
+	i_size_write(inode, offset);
 	down(&mapping->i_shared_sem);
 	if (list_empty(&mapping->i_mmap) &&
list_empty(&mapping->i_mmap_shared))
 		goto out_unlock;
@@ -1077,7 +1077,7 @@ do_expand:
 		goto out_sig;
 	if (offset > inode->i_sb->s_maxbytes)
 		goto out;
-	inode->i_size = offset;
+	i_size_write(inode, offset);
 
 out_truncate:
 	if (inode->i_op && inode->i_op->truncate)
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/nommu.c
linux-2.5.64-isize/mm/nommu.c
--- linux-2.5.64/mm/nommu.c	Tue Mar  4 19:29:34 2003
+++ linux-2.5.64-isize/mm/nommu.c	Thu Mar  6 15:30:42 2003
@@ -46,7 +46,7 @@ int vmtruncate(struct inode *inode, loff
 
 	if (inode->i_size < offset)
 		goto do_expand;
-	inode->i_size = offset;
+	i_size_write(inode) = offset;
 
 	truncate_inode_pages(mapping, offset);
 	goto out_truncate;
@@ -57,7 +57,7 @@ do_expand:
 		goto out_sig;
 	if (offset > inode->i_sb->s_maxbytes)
 		goto out;
-	inode->i_size = offset;
+	i_size_write(inode) = offset;
 
 out_truncate:
 	if (inode->i_op && inode->i_op->truncate) {
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/readahead.c
linux-2.5.64-isize/mm/readahead.c
--- linux-2.5.64/mm/readahead.c	Tue Mar  4 19:28:58 2003
+++ linux-2.5.64-isize/mm/readahead.c	Thu Mar  6 15:30:42 2003
@@ -200,11 +200,12 @@ __do_page_cache_readahead(struct address
 	LIST_HEAD(page_pool);
 	int page_idx;
 	int ret = 0;
+	loff_t isize = i_size_read(inode);
 
-	if (inode->i_size == 0)
+	if (isize == 0)
 		goto out;
 
- 	end_index = ((inode->i_size - 1) >> PAGE_CACHE_SHIFT);
+ 	end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
 
 	/*
 	 * Preallocate as many pages as we will need.
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/shmem.c
linux-2.5.64-isize/mm/shmem.c
--- linux-2.5.64/mm/shmem.c	Tue Mar  4 19:29:17 2003
+++ linux-2.5.64-isize/mm/shmem.c	Thu Mar  6 15:30:42 2003
@@ -295,7 +295,7 @@ static swp_entry_t *shmem_swp_alloc(stru
 	static const swp_entry_t unswapped = {0};
 
 	if (sgp != SGP_WRITE &&
-	    ((loff_t) index << PAGE_CACHE_SHIFT) >= inode->i_size)
+	    ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode))
 		return ERR_PTR(-EINVAL);
 
 	while (!(entry = shmem_swp_entry(info, index, &page))) {
@@ -328,7 +328,7 @@ static swp_entry_t *shmem_swp_alloc(stru
 			return ERR_PTR(-ENOMEM);
 		}
 		if (sgp != SGP_WRITE &&
-		    ((loff_t) index << PAGE_CACHE_SHIFT) >= inode->i_size) {
+		    ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
 			entry = ERR_PTR(-EINVAL);
 			break;
 		}
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/swapfile.c
linux-2.5.64-isize/mm/swapfile.c
--- linux-2.5.64/mm/swapfile.c	Tue Mar  4 19:29:02 2003
+++ linux-2.5.64-isize/mm/swapfile.c	Thu Mar  6 15:30:42 2003
@@ -889,7 +889,7 @@ static int setup_swap_extents(struct swa
 	 */
 	probe_block = 0;
 	page_no = 0;
-	last_block = inode->i_size >> blkbits;
+	last_block = i_size_read(inode) >> blkbits;
 	while ((probe_block + blocks_per_page) <= last_block &&
 			page_no < sis->max) {
 		unsigned block_in_page;
@@ -1259,7 +1259,7 @@ asmlinkage long sys_swapon(const char * 
 	}
 
 	mapping = swap_file->f_dentry->d_inode->i_mapping;
-	swapfilesize = mapping->host->i_size >> PAGE_SHIFT;
+	swapfilesize = i_size_read(mapping->host) >> PAGE_SHIFT;
 
 	error = -EBUSY;
 	for (i = 0 ; i < nr_swapfiles ; i++) {




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2.5.64 2/2] i_size atomic access
  2003-03-08  0:15 [PATCH 2.5.64 2/2] i_size atomic access Daniel McNeil
@ 2003-03-08  0:30 ` Andrew Morton
  2003-03-08  1:26   ` Daniel McNeil
  0 siblings, 1 reply; 5+ messages in thread
From: Andrew Morton @ 2003-03-08  0:30 UTC (permalink / raw)
  To: Daniel McNeil; +Cc: andrea, linux-kernel, shemminger, torvalds

Daniel McNeil <daniel@osdl.org> wrote:
>
> This adds i_seqcnt to inode structure and then uses i_size_read() and
> i_size_write() to provide atomic access to i_size.

Ho hum.  Everybody absolutely hates this, but I guess we should do it :(

> +static inline void i_size_write(struct inode * inode, loff_t i_size)
> +{
> +#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
> +	write_seqcntbegin(&inode->i_size_seqcnt);
> +	inode->i_size = i_size;
> +	write_seqcntend(&inode->i_size_seqcnt);
> +#elif BITS_PER_LONG==32 && defined(CONFIG_PREMPT)
> +	prempt_disable();
> +	inode->i_size = i_size;
> +	prempt_enable();
> +#else
> +	inode->i_size = i_size;
> +#endif
> +}

You've used "PREMPT" and "prempt" throughput the patch.  It is in fact
"PREEMPT" and "preempt".

Could you please fix that up and send me fresh copies?  Probably as
attachments - your mailer wordwrapped the patches.

Thanks.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2.5.64 2/2] i_size atomic access
  2003-03-08  0:30 ` Andrew Morton
@ 2003-03-08  1:26   ` Daniel McNeil
       [not found]     ` <20030308042555.GA31650@delft.aura.cs.cmu.edu>
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel McNeil @ 2003-03-08  1:26 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Andrea Arcangeli, Linux Kernel Mailing List, Stephen Hemminger,
	Linus Torvalds

[-- Attachment #1: Type: text/plain, Size: 1087 bytes --]


On Fri, 2003-03-07 at 16:30, Andrew Morton wrote:
> Daniel McNeil <daniel@osdl.org> wrote:
> >
> > This adds i_seqcnt to inode structure and then uses i_size_read() and
> > i_size_write() to provide atomic access to i_size.
> 
> Ho hum.  Everybody absolutely hates this, but I guess we should do it :(
> 
> > +static inline void i_size_write(struct inode * inode, loff_t i_size)
> > +{
> > +#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
> > +	write_seqcntbegin(&inode->i_size_seqcnt);
> > +	inode->i_size = i_size;
> > +	write_seqcntend(&inode->i_size_seqcnt);
> > +#elif BITS_PER_LONG==32 && defined(CONFIG_PREMPT)
> > +	prempt_disable();
> > +	inode->i_size = i_size;
> > +	prempt_enable();
> > +#else
> > +	inode->i_size = i_size;
> > +#endif
> > +}
> 
> You've used "PREMPT" and "prempt" throughput the patch.  It is in fact
> "PREEMPT" and "preempt".
> 
> Could you please fix that up and send me fresh copies?  Probably as
> attachments - your mailer wordwrapped the patches.
> 
> Thanks.

Here are the updated patches as attachments.

Thanks,

-- 
Daniel McNeil <daniel@osdl.org>

[-- Attachment #2: patch-2.5.64-isize.1 --]
[-- Type: text/x-patch, Size: 1603 bytes --]

diff -urNp -X /home/daniel/dontdiff linux-2.5.64/include/linux/seqlock.h linux-2.5.64-isize/include/linux/seqlock.h
--- linux-2.5.64/include/linux/seqlock.h	Tue Mar  4 19:29:17 2003
+++ linux-2.5.64-isize/include/linux/seqlock.h	Thu Mar  6 15:30:42 2003
@@ -94,6 +94,57 @@ static inline int read_seqretry(const se
 	return (iv & 1) | (sl->sequence ^ iv);
 }
 
+
+/*
+ * Version using sequence counter only. 
+ * This can be used when code has its own mutex protecting the
+ * updating starting before the write_seqcntbeqin() and ending
+ * after the write_seqcntend().
+ */
+
+typedef struct seqcnt {
+	unsigned sequence;
+} seqcnt_t;
+
+#define SEQCNT_ZERO { 0 }
+#define seqcnt_init(x)	do { *(x) = (seqcnt_t) SEQCNT_ZERO; } while (0)
+
+/* Start of read using pointer to a sequence counter only.  */
+static inline unsigned read_seqcntbegin(const seqcnt_t *s)
+{
+	unsigned ret = s->sequence;
+	smp_rmb();
+	return ret;
+}
+
+/* Test if reader processed invalid data.
+ * Equivalent to: iv is odd or sequence number has changed.
+ *                (iv & 1) || (*s != iv)
+ * Using xor saves one conditional branch.
+ */
+static inline int read_seqcntretry(const seqcnt_t *s, unsigned iv)
+{
+	smp_rmb();
+	return (iv & 1) | (s->sequence ^ iv);
+}
+
+
+/* 
+ * Sequence counter only version assumes that callers are using their
+ * own mutexing.
+ */
+static inline void write_seqcntbegin(seqcnt_t *s)
+{
+	s->sequence++;
+	smp_wmb();			
+}	
+
+static inline void write_seqcntend(seqcnt_t *s) 
+{
+	smp_wmb();
+	s->sequence++;
+}
+
 /*
  * Possible sw/hw IRQ protected versions of the interfaces.
  */

[-- Attachment #3: patch-2.5.64-isize.2 --]
[-- Type: text/x-patch, Size: 21874 bytes --]

diff -urNp -X /home/daniel/dontdiff linux-2.5.64/drivers/block/loop.c linux-2.5.64-isize/drivers/block/loop.c
--- linux-2.5.64/drivers/block/loop.c	Tue Mar  4 19:29:22 2003
+++ linux-2.5.64-isize/drivers/block/loop.c	Thu Mar  6 15:30:42 2003
@@ -153,8 +153,9 @@ struct loop_func_table *xfer_funcs[MAX_L
 
 static int figure_loop_size(struct loop_device *lo)
 {
-	loff_t size = lo->lo_backing_file->f_dentry->d_inode->i_mapping->host->i_size;
+	loff_t size = i_size_read(lo->lo_backing_file->f_dentry->d_inode->i_mapping->host);
 	sector_t x;
+	printk("mcneil tmp %Ld %x", size, lo->lo_backing_file->f_dentry->d_inode->i_mapping->host);
 	/*
 	 * Unfortunately, if we want to do I/O on the device,
 	 * the number of 512-byte sectors has to fit into a sector_t.
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/attr.c linux-2.5.64-isize/fs/attr.c
--- linux-2.5.64/fs/attr.c	Tue Mar  4 19:28:59 2003
+++ linux-2.5.64-isize/fs/attr.c	Thu Mar  6 15:30:42 2003
@@ -68,7 +68,7 @@ int inode_setattr(struct inode * inode, 
 	int error = 0;
 
 	if (ia_valid & ATTR_SIZE) {
-		if (attr->ia_size == inode->i_size) {
+		if (attr->ia_size == i_size_read(inode)) {
 			if (ia_valid == ATTR_SIZE)
 				goto out;	/* we can skip lock_kernel() */
 		} else {
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/binfmt_aout.c linux-2.5.64-isize/fs/binfmt_aout.c
--- linux-2.5.64/fs/binfmt_aout.c	Tue Mar  4 19:29:02 2003
+++ linux-2.5.64-isize/fs/binfmt_aout.c	Thu Mar  6 15:30:42 2003
@@ -269,7 +269,7 @@ static int load_aout_binary(struct linux
 	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
 	     N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
 	    N_TRSIZE(ex) || N_DRSIZE(ex) ||
-	    bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+	    i_size_read(bprm->file->f_dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 		return -ENOEXEC;
 	}
 
@@ -454,7 +454,7 @@ static int load_aout_library(struct file
 	/* We come in here for the regular a.out style of shared libraries */
 	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
 	    N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
-	    inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+	    i_size_read(inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 		goto out;
 	}
 
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/block_dev.c linux-2.5.64-isize/fs/block_dev.c
--- linux-2.5.64/fs/block_dev.c	Tue Mar  4 19:29:56 2003
+++ linux-2.5.64-isize/fs/block_dev.c	Thu Mar  6 15:30:42 2003
@@ -29,7 +29,7 @@
 static sector_t max_block(struct block_device *bdev)
 {
 	sector_t retval = ~((sector_t)0);
-	loff_t sz = bdev->bd_inode->i_size;
+	loff_t sz = i_size_read(bdev->bd_inode);
 
 	if (sz) {
 		unsigned int size = block_size(bdev);
@@ -156,7 +156,7 @@ static int blkdev_commit_write(struct fi
 static loff_t block_llseek(struct file *file, loff_t offset, int origin)
 {
 	/* ewww */
-	loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size;
+	loff_t size = i_size_read(file->f_dentry->d_inode->i_bdev->bd_inode);
 	loff_t retval;
 
 	lock_kernel();
@@ -549,7 +549,7 @@ int __check_disk_change(dev_t dev)
 static void bd_set_size(struct block_device *bdev, loff_t size)
 {
 	unsigned bsize = bdev_hardsect_size(bdev);
-	bdev->bd_inode->i_size = size;
+	i_size_write(bdev->bd_inode, size);
 	while (bsize < PAGE_CACHE_SIZE) {
 		if (size & bsize)
 			break;
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/buffer.c linux-2.5.64-isize/fs/buffer.c
--- linux-2.5.64/fs/buffer.c	Tue Mar  4 19:29:22 2003
+++ linux-2.5.64-isize/fs/buffer.c	Thu Mar  6 15:30:42 2003
@@ -1623,7 +1623,7 @@ static int __block_write_full_page(struc
 
 	BUG_ON(!PageLocked(page));
 
-	last_block = (inode->i_size - 1) >> inode->i_blkbits;
+	last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;
 
 	if (!page_has_buffers(page)) {
 		if (!PageUptodate(page))
@@ -1961,7 +1961,7 @@ int block_read_full_page(struct page *pa
 
 	blocks = PAGE_CACHE_SIZE >> inode->i_blkbits;
 	iblock = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
-	lblock = (inode->i_size+blocksize-1) >> inode->i_blkbits;
+	lblock = (i_size_read(inode)+blocksize-1) >> inode->i_blkbits;
 	bh = head;
 	nr = 0;
 	i = 0;
@@ -2186,8 +2186,12 @@ int generic_commit_write(struct file *fi
 	struct inode *inode = page->mapping->host;
 	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
 	__block_commit_write(inode,page,from,to);
+	/*
+	 * No need to use i_size_read() here, the i_size
+	 * cannot change under us because we hold i_sem.
+	 */
 	if (pos > inode->i_size) {
-		inode->i_size = pos;
+		i_size_write(inode, pos);
 		mark_inode_dirty(inode);
 	}
 	return 0;
@@ -2339,7 +2343,7 @@ int nobh_commit_write(struct file *file,
 
 	set_page_dirty(page);
 	if (pos > inode->i_size) {
-		inode->i_size = pos;
+		i_size_write(inode, pos);
 		mark_inode_dirty(inode);
 	}
 	return 0;
@@ -2469,7 +2473,8 @@ int block_write_full_page(struct page *p
 			struct writeback_control *wbc)
 {
 	struct inode * const inode = page->mapping->host;
-	const unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	loff_t i_size = i_size_read(inode);
+	const unsigned long end_index = i_size >> PAGE_CACHE_SHIFT;
 	unsigned offset;
 	void *kaddr;
 
@@ -2478,7 +2483,7 @@ int block_write_full_page(struct page *p
 		return __block_write_full_page(inode, page, get_block, wbc);
 
 	/* Is the page fully outside i_size? (truncate in progress) */
-	offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+	offset = i_size & (PAGE_CACHE_SIZE-1);
 	if (page->index >= end_index+1 || !offset) {
 		/*
 		 * The page may have dirty, unmapped buffers.  For example,
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/ext3/inode.c linux-2.5.64-isize/fs/ext3/inode.c
--- linux-2.5.64/fs/ext3/inode.c	Tue Mar  4 19:29:30 2003
+++ linux-2.5.64-isize/fs/ext3/inode.c	Thu Mar  6 15:30:42 2003
@@ -1158,7 +1158,7 @@ static int ext3_commit_write(struct file
 		if (!partial)
 			SetPageUptodate(page);
 		if (pos > inode->i_size)
-			inode->i_size = pos;
+			i_size_write(inode, pos);
 		EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
 	} else {
 		if (ext3_should_order_data(inode)) {
@@ -1473,7 +1473,7 @@ out_stop:
 			loff_t end = offset + ret;
 			if (end > inode->i_size) {
 				ei->i_disksize = end;
-				inode->i_size = end;
+				i_size_write(inode, end);
 				err = ext3_mark_inode_dirty(handle, inode);
 				if (!ret) 
 					ret = err;
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/inode.c linux-2.5.64-isize/fs/inode.c
--- linux-2.5.64/fs/inode.c	Tue Mar  4 19:29:54 2003
+++ linux-2.5.64-isize/fs/inode.c	Thu Mar  6 15:30:42 2003
@@ -188,6 +188,7 @@ void inode_init_once(struct inode *inode
 	INIT_LIST_HEAD(&inode->i_data.i_mmap);
 	INIT_LIST_HEAD(&inode->i_data.i_mmap_shared);
 	spin_lock_init(&inode->i_lock);
+	i_size_ordered_init(inode);
 }
 
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/ioctl.c linux-2.5.64-isize/fs/ioctl.c
--- linux-2.5.64/fs/ioctl.c	Tue Mar  4 19:29:03 2003
+++ linux-2.5.64-isize/fs/ioctl.c	Thu Mar  6 15:30:42 2003
@@ -40,7 +40,7 @@ static int file_ioctl(struct file *filp,
 				return -EBADF;
 			return put_user(inode->i_sb->s_blocksize, (int *) arg);
 		case FIONREAD:
-			return put_user(inode->i_size - filp->f_pos, (int *) arg);
+			return put_user(i_size_read(inode) - filp->f_pos, (int *) arg);
 	}
 	if (filp->f_op && filp->f_op->ioctl)
 		return filp->f_op->ioctl(inode, filp, cmd, arg);
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/libfs.c linux-2.5.64-isize/fs/libfs.c
--- linux-2.5.64/fs/libfs.c	Tue Mar  4 19:28:53 2003
+++ linux-2.5.64-isize/fs/libfs.c	Thu Mar  6 15:30:42 2003
@@ -327,8 +327,12 @@ int simple_commit_write(struct file *fil
 	struct inode *inode = page->mapping->host;
 	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
 
+	/*
+	 * No need to use i_size_read() here, the i_size
+	 * cannot change under us because we hold the i_sem.
+	 */
 	if (pos > inode->i_size)
-		inode->i_size = pos;
+		i_size_write(inode, pos);
 	set_page_dirty(page);
 	return 0;
 }
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/locks.c linux-2.5.64-isize/fs/locks.c
--- linux-2.5.64/fs/locks.c	Tue Mar  4 19:29:51 2003
+++ linux-2.5.64-isize/fs/locks.c	Thu Mar  6 15:30:42 2003
@@ -292,7 +292,7 @@ static int flock_to_posix_lock(struct fi
 		start = filp->f_pos;
 		break;
 	case 2: /*SEEK_END*/
-		start = filp->f_dentry->d_inode->i_size;
+		start = i_size_read(filp->f_dentry->d_inode);
 		break;
 	default:
 		return -EINVAL;
@@ -342,7 +342,7 @@ static int flock64_to_posix_lock(struct 
 		start = filp->f_pos;
 		break;
 	case 2: /*SEEK_END*/
-		start = filp->f_dentry->d_inode->i_size;
+		start = i_size_read(filp->f_dentry->d_inode);
 		break;
 	default:
 		return -EINVAL;
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/mpage.c linux-2.5.64-isize/fs/mpage.c
--- linux-2.5.64/fs/mpage.c	Tue Mar  4 19:29:03 2003
+++ linux-2.5.64-isize/fs/mpage.c	Thu Mar  6 15:30:42 2003
@@ -227,7 +227,7 @@ do_mpage_readpage(struct bio *bio, struc
 		goto confused;
 
 	block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);
-	last_block = (inode->i_size + blocksize - 1) >> blkbits;
+	last_block = (i_size_read(inode) + blocksize - 1) >> blkbits;
 
 	bh.b_page = page;
 	for (page_block = 0; page_block < blocks_per_page;
@@ -459,7 +459,7 @@ mpage_writepage(struct bio *bio, struct 
 	 */
 	BUG_ON(!PageUptodate(page));
 	block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits);
-	last_block = (inode->i_size - 1) >> blkbits;
+	last_block = (i_size_read(inode) - 1) >> blkbits;
 	map_bh.b_page = page;
 	for (page_block = 0; page_block < blocks_per_page; ) {
 
@@ -489,9 +489,9 @@ mpage_writepage(struct bio *bio, struct 
 
 	first_unmapped = page_block;
 
-	end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
 	if (page->index >= end_index) {
-		unsigned offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
+		unsigned offset = i_size_read(inode) & (PAGE_CACHE_SIZE - 1);
 		char *kaddr;
 
 		if (page->index > end_index || !offset)
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/open.c linux-2.5.64-isize/fs/open.c
--- linux-2.5.64/fs/open.c	Tue Mar  4 19:28:57 2003
+++ linux-2.5.64-isize/fs/open.c	Thu Mar  6 15:30:42 2003
@@ -908,7 +908,7 @@ asmlinkage long sys_vhangup(void)
  */
 int generic_file_open(struct inode * inode, struct file * filp)
 {
-	if (!(filp->f_flags & O_LARGEFILE) && inode->i_size > MAX_NON_LFS)
+	if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
 		return -EFBIG;
 	return 0;
 }
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/quota_v1.c linux-2.5.64-isize/fs/quota_v1.c
--- linux-2.5.64/fs/quota_v1.c	Tue Mar  4 19:29:32 2003
+++ linux-2.5.64-isize/fs/quota_v1.c	Thu Mar  6 15:30:42 2003
@@ -128,12 +128,14 @@ static int v1_check_quota_file(struct su
 	mm_segment_t fs;
 	ssize_t size;
 	loff_t offset = 0;
+	loff_t isize;
 	static const uint quota_magics[] = V2_INITQMAGICS;
 
-	if (!inode->i_size)
+	isize = i_size_read(inode);
+	if (!isize)
 		return 0;
-	blocks = inode->i_size >> BLOCK_SIZE_BITS;
-	off = inode->i_size & (BLOCK_SIZE - 1);
+	blocks = isize >> BLOCK_SIZE_BITS;
+	off = isize & (BLOCK_SIZE - 1);
 	if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % sizeof(struct v1_disk_dqblk))
 		return 0;
 	/* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/fs/stat.c linux-2.5.64-isize/fs/stat.c
--- linux-2.5.64/fs/stat.c	Tue Mar  4 19:29:02 2003
+++ linux-2.5.64-isize/fs/stat.c	Thu Mar  6 15:30:42 2003
@@ -28,7 +28,7 @@ void generic_fillattr(struct inode *inod
 	stat->atime = inode->i_atime;
 	stat->mtime = inode->i_mtime;
 	stat->ctime = inode->i_ctime;
-	stat->size = inode->i_size;
+	stat->size = i_size_read(inode);
 	stat->blocks = inode->i_blocks;
 	stat->blksize = inode->i_blksize;
 }
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/include/linux/fs.h linux-2.5.64-isize/include/linux/fs.h
--- linux-2.5.64/include/linux/fs.h	Tue Mar  4 19:29:03 2003
+++ linux-2.5.64-isize/include/linux/fs.h	Thu Mar  6 15:30:42 2003
@@ -353,6 +353,17 @@ struct block_device {
 	struct gendisk *	bd_disk;
 };
 
+/*
+ * Use sequence counter to get consistent i_size on 32-bit processors.
+ */
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+#include <linux/seqlock.h>
+#define __NEED_I_SIZE_ORDERED
+#define i_size_ordered_init(inode) seqcnt_init(&inode->i_size_seqcnt)
+#else
+#define i_size_ordered_init(inode) do { } while (0)
+#endif
+
 struct inode {
 	struct hlist_node	i_hash;
 	struct list_head	i_list;
@@ -402,7 +413,59 @@ struct inode {
 	union {
 		void		*generic_ip;
 	} u;
+#ifdef __NEED_I_SIZE_ORDERED
+	seqcnt_t		i_size_seqcnt;
+#endif
 };
+
+/*
+ * NOTE: in a 32bit arch with a preemptable kernel and
+ * an UP compile the i_size_read/write must be atomic
+ * with respect to the local cpu (unlike with preempt disabled),
+ * but they don't need to be atomic with respect to other cpus like in
+ * true SMP (so they need either to either locally disable irq around
+ * the read or for example on x86 they can be still implemented as a
+ * cmpxchg8b without the need of the lock prefix). For SMP compiles
+ * and 64bit archs it makes no difference if preempt is enabled or not.
+ */
+static inline loff_t i_size_read(struct inode * inode)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	loff_t i_size;
+	unsigned int seq;
+
+	do {
+		seq = read_seqcntbegin(&inode->i_size_seqcnt);
+		i_size = inode->i_size;
+	} while (read_seqcntretry(&inode->i_size_seqcnt, seq));
+	return i_size;
+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
+	loff_t i_size;
+
+	preempt_disable();
+	i_size = inode->i_size;
+	preempt_enable();
+	return i_size;
+#else
+	return inode->i_size;
+#endif
+}
+
+
+static inline void i_size_write(struct inode * inode, loff_t i_size)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+	write_seqcntbegin(&inode->i_size_seqcnt);
+	inode->i_size = i_size;
+	write_seqcntend(&inode->i_size_seqcnt);
+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
+	preempt_disable();
+	inode->i_size = i_size;
+	preempt_enable();
+#else
+	inode->i_size = i_size;
+#endif
+}
 
 struct fown_struct {
 	rwlock_t lock;          /* protects pid, uid, euid fields */
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/ipc/shm.c linux-2.5.64-isize/ipc/shm.c
--- linux-2.5.64/ipc/shm.c	Tue Mar  4 19:29:19 2003
+++ linux-2.5.64-isize/ipc/shm.c	Thu Mar  6 15:30:42 2003
@@ -691,7 +691,7 @@ asmlinkage long sys_shmat (int shmid, ch
 	}
 		
 	file = shp->shm_file;
-	size = file->f_dentry->d_inode->i_size;
+	size = i_size_read(file->f_dentry->d_inode);
 	shp->shm_nattch++;
 	shm_unlock(shp);
 
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/filemap.c linux-2.5.64-isize/mm/filemap.c
--- linux-2.5.64/mm/filemap.c	Tue Mar  4 19:29:15 2003
+++ linux-2.5.64-isize/mm/filemap.c	Thu Mar  6 15:30:42 2003
@@ -543,14 +543,15 @@ void do_generic_mapping_read(struct addr
 	for (;;) {
 		struct page *page;
 		unsigned long end_index, nr, ret;
+		loff_t isize = i_size_read(inode);
 
-		end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+		end_index = isize >> PAGE_CACHE_SHIFT;
 			
 		if (index > end_index)
 			break;
 		nr = PAGE_CACHE_SIZE;
 		if (index == end_index) {
-			nr = inode->i_size & ~PAGE_CACHE_MASK;
+			nr = isize & ~PAGE_CACHE_MASK;
 			if (nr <= offset)
 				break;
 		}
@@ -751,7 +752,7 @@ __generic_file_aio_read(struct kiocb *io
 		retval = 0;
 		if (!count)
 			goto out; /* skip atime */
-		size = inode->i_size;
+		size = i_size_read(inode);
 		if (pos < size) {
 			retval = generic_file_direct_IO(READ, iocb,
 						iov, pos, nr_segs);
@@ -940,7 +941,7 @@ retry_all:
 	 * An external ptracer can access pages that normally aren't
 	 * accessible..
 	 */
-	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	if ((pgoff >= size) && (area->vm_mm == current->mm))
 		return NULL;
 
@@ -1208,7 +1209,7 @@ static int filemap_populate(struct vm_ar
 	int err;
 
 repeat:
-	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	if (pgoff + (len >> PAGE_CACHE_SHIFT) > size)
 		return -EINVAL;
 
@@ -1497,7 +1498,7 @@ inline int generic_write_checks(struct i
 	if (!isblk) {
 		/* FIXME: this is for backwards compatibility with 2.4 */
 		if (file->f_flags & O_APPEND)
-                        *pos = inode->i_size;
+                        *pos = i_size_read(inode);
 
 		if (limit != RLIM_INFINITY) {
 			if (*pos >= limit) {
@@ -1545,15 +1546,17 @@ inline int generic_write_checks(struct i
 		if (unlikely(*pos + *count > inode->i_sb->s_maxbytes))
 			*count = inode->i_sb->s_maxbytes - *pos;
 	} else {
+		loff_t isize;
 		if (bdev_read_only(inode->i_bdev))
 			return -EPERM;
-		if (*pos >= inode->i_size) {
-			if (*count || *pos > inode->i_size)
+		isize = i_size_read(inode);
+		if (*pos >= isize) {
+			if (*count || *pos > isize)
 				return -ENOSPC;
 		}
 
-		if (*pos + *count > inode->i_size)
-			*count = inode->i_size - *pos;
+		if (*pos + *count > isize)
+			*count = isize - *pos;
 	}
 	return 0;
 }
@@ -1640,8 +1643,8 @@ generic_file_aio_write_nolock(struct kio
 					iov, pos, nr_segs);
 		if (written > 0) {
 			loff_t end = pos + written;
-			if (end > inode->i_size && !isblk) {
-				inode->i_size = end;
+			if (end > i_size_read(inode) && !isblk) {
+				i_size_write(inode,  end);
 				mark_inode_dirty(inode);
 			}
 			*ppos = end;
@@ -1685,14 +1688,15 @@ generic_file_aio_write_nolock(struct kio
 
 		status = a_ops->prepare_write(file, page, offset, offset+bytes);
 		if (unlikely(status)) {
+			loff_t isize = i_size_read(inode);
 			/*
 			 * prepare_write() may have instantiated a few blocks
 			 * outside i_size.  Trim these off again.
 			 */
 			unlock_page(page);
 			page_cache_release(page);
-			if (pos + bytes > inode->i_size)
-				vmtruncate(inode, inode->i_size);
+			if (pos + bytes > isize)
+				vmtruncate(inode, isize);
 			break;
 		}
 		if (likely(nr_segs == 1))
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/memory.c linux-2.5.64-isize/mm/memory.c
--- linux-2.5.64/mm/memory.c	Tue Mar  4 19:29:18 2003
+++ linux-2.5.64-isize/mm/memory.c	Thu Mar  6 15:30:42 2003
@@ -1055,7 +1055,7 @@ int vmtruncate(struct inode * inode, lof
 
 	if (inode->i_size < offset)
 		goto do_expand;
-	inode->i_size = offset;
+	i_size_write(inode, offset);
 	down(&mapping->i_shared_sem);
 	if (list_empty(&mapping->i_mmap) && list_empty(&mapping->i_mmap_shared))
 		goto out_unlock;
@@ -1077,7 +1077,7 @@ do_expand:
 		goto out_sig;
 	if (offset > inode->i_sb->s_maxbytes)
 		goto out;
-	inode->i_size = offset;
+	i_size_write(inode, offset);
 
 out_truncate:
 	if (inode->i_op && inode->i_op->truncate)
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/nommu.c linux-2.5.64-isize/mm/nommu.c
--- linux-2.5.64/mm/nommu.c	Tue Mar  4 19:29:34 2003
+++ linux-2.5.64-isize/mm/nommu.c	Thu Mar  6 15:30:42 2003
@@ -46,7 +46,7 @@ int vmtruncate(struct inode *inode, loff
 
 	if (inode->i_size < offset)
 		goto do_expand;
-	inode->i_size = offset;
+	i_size_write(inode) = offset;
 
 	truncate_inode_pages(mapping, offset);
 	goto out_truncate;
@@ -57,7 +57,7 @@ do_expand:
 		goto out_sig;
 	if (offset > inode->i_sb->s_maxbytes)
 		goto out;
-	inode->i_size = offset;
+	i_size_write(inode) = offset;
 
 out_truncate:
 	if (inode->i_op && inode->i_op->truncate) {
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/readahead.c linux-2.5.64-isize/mm/readahead.c
--- linux-2.5.64/mm/readahead.c	Tue Mar  4 19:28:58 2003
+++ linux-2.5.64-isize/mm/readahead.c	Thu Mar  6 15:30:42 2003
@@ -200,11 +200,12 @@ __do_page_cache_readahead(struct address
 	LIST_HEAD(page_pool);
 	int page_idx;
 	int ret = 0;
+	loff_t isize = i_size_read(inode);
 
-	if (inode->i_size == 0)
+	if (isize == 0)
 		goto out;
 
- 	end_index = ((inode->i_size - 1) >> PAGE_CACHE_SHIFT);
+ 	end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
 
 	/*
 	 * Preallocate as many pages as we will need.
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/shmem.c linux-2.5.64-isize/mm/shmem.c
--- linux-2.5.64/mm/shmem.c	Tue Mar  4 19:29:17 2003
+++ linux-2.5.64-isize/mm/shmem.c	Thu Mar  6 15:30:42 2003
@@ -295,7 +295,7 @@ static swp_entry_t *shmem_swp_alloc(stru
 	static const swp_entry_t unswapped = {0};
 
 	if (sgp != SGP_WRITE &&
-	    ((loff_t) index << PAGE_CACHE_SHIFT) >= inode->i_size)
+	    ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode))
 		return ERR_PTR(-EINVAL);
 
 	while (!(entry = shmem_swp_entry(info, index, &page))) {
@@ -328,7 +328,7 @@ static swp_entry_t *shmem_swp_alloc(stru
 			return ERR_PTR(-ENOMEM);
 		}
 		if (sgp != SGP_WRITE &&
-		    ((loff_t) index << PAGE_CACHE_SHIFT) >= inode->i_size) {
+		    ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
 			entry = ERR_PTR(-EINVAL);
 			break;
 		}
diff -urNp -X /home/daniel/dontdiff linux-2.5.64/mm/swapfile.c linux-2.5.64-isize/mm/swapfile.c
--- linux-2.5.64/mm/swapfile.c	Tue Mar  4 19:29:02 2003
+++ linux-2.5.64-isize/mm/swapfile.c	Thu Mar  6 15:30:42 2003
@@ -889,7 +889,7 @@ static int setup_swap_extents(struct swa
 	 */
 	probe_block = 0;
 	page_no = 0;
-	last_block = inode->i_size >> blkbits;
+	last_block = i_size_read(inode) >> blkbits;
 	while ((probe_block + blocks_per_page) <= last_block &&
 			page_no < sis->max) {
 		unsigned block_in_page;
@@ -1259,7 +1259,7 @@ asmlinkage long sys_swapon(const char * 
 	}
 
 	mapping = swap_file->f_dentry->d_inode->i_mapping;
-	swapfilesize = mapping->host->i_size >> PAGE_SHIFT;
+	swapfilesize = i_size_read(mapping->host) >> PAGE_SHIFT;
 
 	error = -EBUSY;
 	for (i = 0 ; i < nr_swapfiles ; i++) {

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2.5.64 2/2] i_size atomic access
       [not found]       ` <20030307203340.5e025ef0.akpm@digeo.com>
@ 2003-03-10 13:16         ` Andrea Arcangeli
  2003-03-10 17:22           ` Daniel McNeil
  0 siblings, 1 reply; 5+ messages in thread
From: Andrea Arcangeli @ 2003-03-10 13:16 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Jan Harkes, daniel, linux-kernel, shemminger, torvalds

On Fri, Mar 07, 2003 at 08:33:40PM -0800, Andrew Morton wrote:
> Jan Harkes <jaharkes@cs.cmu.edu> wrote:
> >
> > On Fri, Mar 07, 2003 at 05:26:31PM -0800, Daniel McNeil wrote:
> > > On Fri, 2003-03-07 at 16:30, Andrew Morton wrote:
> > > > Daniel McNeil <daniel@osdl.org> wrote:
> > > > > This adds i_seqcnt to inode structure and then uses i_size_read() and
> > > > > i_size_write() to provide atomic access to i_size.
> > > > 
> > > > Ho hum.  Everybody absolutely hates this, but I guess we should do it :(
> > 
> > I am really curious whether this patch is really all that useful, has
> > anyone ever noticed enough lock contention on inode semaphore caused by
> > accessing i_size? Whenever i_size changes it needs to be locked down
> > either way because mappings have to be extended or truncated.
> 
> The problem is not lock contention.  The problem is that the read() paths are
> performing nonatomic reads of a 64-bit value.  If a writer is updating i_size
> at the same time the reader can see grossly incorrect values.
> 
> It's such a remote problem that nobody really has the heart to do anything
> about it.  But it's there...

well really this is fixed in my tree and in some distribution kernels
for half an year, it's true only the major fs are been taken care of,
but definitely somebody had the heart to do something about it 8)

> > A quick grep shows that there are 619 references to ->i_size in the
> > various filesystem subdirs.
> 
> Most of these are not inode->i_size.  Yes, there are i_size references in
> filesystems, but not many.  And the infrastructure is there to mop those up.
> 
> If we choose to.  I'm still not sure I want to do this :(

There is no other way, some cpu can't even do it atomically (hence the
need of the sequence number approch).

Also note that the atomicity isn't needed everywhere, for example if you
read i_size in the write paths you don't need to use i_size_read, but
you can read with inode->i_size as usual, which is faster and in turn
recommended.

I described the locking rules here:

	http://groups.google.com/groups?q=i_size_read&hl=en&lr=&ie=UTF-8&selm=20020717225504.GA994%40dualathlon.random&rnum=2

	  The rules are: 1) i_size_write must be used for all i_size
	  updates (at least when there can be potential parallel readers
	  outside the i_sem), 2) i_size_read must be used for all lockless
	  reads when an i_size change can happen from under us.
	  
Andrea

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2.5.64 2/2] i_size atomic access
  2003-03-10 13:16         ` Andrea Arcangeli
@ 2003-03-10 17:22           ` Daniel McNeil
  0 siblings, 0 replies; 5+ messages in thread
From: Daniel McNeil @ 2003-03-10 17:22 UTC (permalink / raw)
  To: Andrea Arcangeli
  Cc: Andrew Morton, Jan Harkes, Linux Kernel Mailing List,
	Stephen Hemminger, Linus Torvalds

On Mon, 2003-03-10 at 05:16, Andrea Arcangeli wrote:
> On Fri, Mar 07, 2003 at 08:33:40PM -0800, Andrew Morton wrote:
> > Jan Harkes <jaharkes@cs.cmu.edu> wrote:
> > >
> > > On Fri, Mar 07, 2003 at 05:26:31PM -0800, Daniel McNeil wrote:
> > > > On Fri, 2003-03-07 at 16:30, Andrew Morton wrote:
> > > > > Daniel McNeil <daniel@osdl.org> wrote:
> > > > > > This adds i_seqcnt to inode structure and then uses i_size_read() and
> > > > > > i_size_write() to provide atomic access to i_size.
> > > > > 
> > > > > Ho hum.  Everybody absolutely hates this, but I guess we should do it :(
> > > 
> > > I am really curious whether this patch is really all that useful, has
> > > anyone ever noticed enough lock contention on inode semaphore caused by
> > > accessing i_size? Whenever i_size changes it needs to be locked down
> > > either way because mappings have to be extended or truncated.
> > 
> > The problem is not lock contention.  The problem is that the read() paths are
> > performing nonatomic reads of a 64-bit value.  If a writer is updating i_size
> > at the same time the reader can see grossly incorrect values.
> > 
> > It's such a remote problem that nobody really has the heart to do anything
> > about it.  But it's there...
> 
> well really this is fixed in my tree and in some distribution kernels
> for half an year, it's true only the major fs are been taken care of,
> but definitely somebody had the heart to do something about it 8)
> 
> > > A quick grep shows that there are 619 references to ->i_size in the
> > > various filesystem subdirs.
> > 
> > Most of these are not inode->i_size.  Yes, there are i_size references in
> > filesystems, but not many.  And the infrastructure is there to mop those up.
> > 
> > If we choose to.  I'm still not sure I want to do this :(
> 
> There is no other way, some cpu can't even do it atomically (hence the
> need of the sequence number approch).
> 
> Also note that the atomicity isn't needed everywhere, for example if you
> read i_size in the write paths you don't need to use i_size_read, but
> you can read with inode->i_size as usual, which is faster and in turn
> recommended.
> 
> I described the locking rules here:
> 
> 	http://groups.google.com/groups?q=i_size_read&hl=en&lr=&ie=UTF-8&selm=20020717225504.GA994%40dualathlon.random&rnum=2
> 
> 	  The rules are: 1) i_size_write must be used for all i_size
> 	  updates (at least when there can be potential parallel readers
> 	  outside the i_sem), 2) i_size_read must be used for all lockless
> 	  reads when an i_size change can happen from under us.
> 	  
> Andrea

I agree with Andrea and think we should fix this.  The sequence number
approach works for all architectures without much overhead.  i_size_read
does not pollute the cache.  I chose not to port the cmpxchg8/get64_bit
part of Andrea's patch from 2.4, since it is more complicated and
cmpxchg8 does write the cache line.

I did test the changes using a simple program that forks 2 processes
on a 2-proc machine. One does stat64() and the other does
truncate(4GB-1) / truncate(4G) in a large loop.  Without the patch,
the stat does rarely get an i_size of 0 or 8GB-1.  With the patch,
the stat() always sees a correct i_size. I typically had to loop
for 5 million stat()s before I would see the problem.


-- 
Daniel McNeil <daniel@osdl.org>


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2003-03-10 17:12 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-03-08  0:15 [PATCH 2.5.64 2/2] i_size atomic access Daniel McNeil
2003-03-08  0:30 ` Andrew Morton
2003-03-08  1:26   ` Daniel McNeil
     [not found]     ` <20030308042555.GA31650@delft.aura.cs.cmu.edu>
     [not found]       ` <20030307203340.5e025ef0.akpm@digeo.com>
2003-03-10 13:16         ` Andrea Arcangeli
2003-03-10 17:22           ` Daniel McNeil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).