Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1732

kernel-2.6.18-238.el5.src.rpm

From: Mikulas Patocka <mpatocka@redhat.com>
Date: Thu, 9 Sep 2010 13:04:55 -0400
Subject: [md] dm: fix deadlock with fsync vs. resize in lvm
Message-id: <Pine.LNX.4.64.1009090858540.26750@hs20-bc2-1.build.redhat.com>
Patchwork-id: 28188
O-Subject: [PATCH RHEL5] bz624068: deadlock: fsync vs. resize in lvm
Bugzilla: 624068
RH-Acked-by: Jonathan E Brassow <jbrassow@redhat.com>

Hi

This fixes bz624068 and several additional bugs found during review.

Upstream status: none. But the issue is urgent. Please review carefully.
The patch is long, but almost all it does is chaning inode->i_size to
i_size_read(inode), so it should be easy to review. Additional
considerations that were reviewed are in bugzilla.

Testing: compiled kernel and verified basic lvm functionality w.r.t.
resizing. I don't have a testcase, I think Milan Broz has, so he can try
it, or it could be tested on the original failing site.

Mikulas


diff --git a/block/ioctl.c b/block/ioctl.c
index 9fddb99..ddefff7 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -185,11 +185,11 @@ static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev,
 	case BLKRRPART:
 		return blkdev_reread_part(bdev);
 	case BLKGETSIZE:
-		if ((bdev->bd_inode->i_size >> 9) > ~0UL)
+		if ((i_size_read(bdev->bd_inode) >> 9) > ~0UL)
 			return -EFBIG;
-		return put_ulong(arg, bdev->bd_inode->i_size >> 9);
+		return put_ulong(arg, i_size_read(bdev->bd_inode) >> 9);
 	case BLKGETSIZE64:
-		return put_u64(arg, bdev->bd_inode->i_size);
+		return put_u64(arg, i_size_read(bdev->bd_inode));
 	case BLKTRACESTART:
 	case BLKTRACESTOP:
 	case BLKTRACESETUP:
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 830dc1d..1032232 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -3155,7 +3155,7 @@ static void handle_bad_sector(struct bio *bio)
 			bdevname(bio->bi_bdev, b),
 			bio->bi_rw,
 			(unsigned long long)bio->bi_sector + bio_sectors(bio),
-			(long long)(bio->bi_bdev->bd_inode->i_size >> 9));
+			(long long)(i_size_read(bio->bi_bdev->bd_inode) >> 9));
 
 	set_bit(BIO_EOF, &bio->bi_flags);
 }
@@ -3194,7 +3194,7 @@ void generic_make_request(struct bio *bio)
 
 	might_sleep();
 	/* Test device or partition size, when known. */
-	maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
+	maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9;
 	if (maxsector) {
 		sector_t sector = bio->bi_sector;
 
@@ -3260,7 +3260,7 @@ end_io:
 		old_sector = bio->bi_sector;
 		old_dev = bio->bi_bdev->bd_dev;
 
-		maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
+		maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9;
 		if (maxsector) {
 			sector_t sector = bio->bi_sector;
 
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h
index aec48ed..7cd064a 100644
--- a/drivers/md/dm-snap.h
+++ b/drivers/md/dm-snap.h
@@ -211,7 +211,7 @@ int dm_create_transient(struct exception_store *store);
  */
 static inline sector_t get_dev_size(struct block_device *bdev)
 {
-	return bdev->bd_inode->i_size >> SECTOR_SHIFT;
+	return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
 }
 
 static inline chunk_t sector_to_chunk(struct dm_snapshot *s, sector_t sector)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 461e686..036092e 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1152,9 +1152,7 @@ static void __set_size(struct mapped_device *md, sector_t size)
 {
 	set_capacity(md->disk, size);
 
-	mutex_lock(&md->suspended_bdev->bd_inode->i_mutex);
 	i_size_write(md->suspended_bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
-	mutex_unlock(&md->suspended_bdev->bd_inode->i_mutex);
 }
 
 static int __bind(struct mapped_device *md, struct dm_table *t)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 05c8873..1272711 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -341,7 +341,7 @@ static struct mdk_personality *find_pers(int level, char *clevel)
 
 static inline sector_t calc_dev_sboffset(struct block_device *bdev)
 {
-	sector_t size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+	sector_t size = i_size_read(bdev->bd_inode) >> BLOCK_SIZE_BITS;
 	return MD_NEW_SIZE_BLOCKS(size);
 }
 
@@ -1010,7 +1010,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
 	 */
 	switch(minor_version) {
 	case 0:
-		sb_offset = rdev->bdev->bd_inode->i_size >> 9;
+		sb_offset = i_size_read(rdev->bdev->bd_inode) >> 9;
 		sb_offset -= 8*2;
 		sb_offset &= ~(sector_t)(4*2-1);
 		/* convert from sectors to K */
@@ -1093,7 +1093,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
 			ret = 0;
 	}
 	if (minor_version) 
-		rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2;
+		rdev->size = ((i_size_read(rdev->bdev->bd_inode)>>9) - le64_to_cpu(sb->data_offset)) / 2;
 	else
 		rdev->size = rdev->sb_offset;
 	if (rdev->size < le64_to_cpu(sb->data_size)/2)
@@ -2030,7 +2030,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
 	atomic_set(&rdev->read_errors, 0);
 	atomic_set(&rdev->corrected_errors, 0);
 
-	size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+	size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
 	if (!size) {
 		printk(KERN_WARNING 
 			"md: %s has zero or unknown size, marking faulty!\n",
@@ -3841,7 +3841,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
 
 		if (!mddev->persistent) {
 			printk(KERN_INFO "md: nonpersistent superblock ...\n");
-			rdev->sb_offset = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+			rdev->sb_offset = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
 		} else 
 			rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
 		rdev->size = calc_dev_size(rdev, mddev->chunk_size);
@@ -3917,7 +3917,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
 		rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
 	else
 		rdev->sb_offset =
-			rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+			i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
 
 	size = calc_dev_size(rdev, mddev->chunk_size);
 	rdev->size = size;
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 401c6a2..31c69bb 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -337,7 +337,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 
 	sprintf(dev->mtd.name, "block2mtd: %s", devname);
 
-	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
+	dev->mtd.size = i_size_read(dev->blkdev->bd_inode) & PAGE_MASK;
 	dev->mtd.erasesize = erase_size;
 	dev->mtd.writesize = 1;
 	dev->mtd.type = MTD_RAM;
diff --git a/fs/read_write.c b/fs/read_write.c
index c5b80d9..2692187 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -36,7 +36,7 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
 	mutex_lock(&inode->i_mutex);
 	switch (origin) {
 		case 2:
-			offset += inode->i_size;
+			offset += i_size_read(inode);
 			break;
 		case 1:
 			offset += file->f_pos;
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index 1f03c0f..fe268c4 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -245,7 +245,7 @@ fill_pre_wcc(struct svc_fh *fhp)
 	if (!fhp->fh_pre_saved) {
 		fhp->fh_pre_mtime = inode->i_mtime;
 		fhp->fh_pre_ctime = inode->i_ctime;
-			fhp->fh_pre_size  = inode->i_size;
+			fhp->fh_pre_size  = i_size_read(inode);
 			fhp->fh_pre_saved = 1;
 	}
 }
diff --git a/net/tux/input.c b/net/tux/input.c
index 34275b1..b5de27b 100644
--- a/net/tux/input.c
+++ b/net/tux/input.c
@@ -163,7 +163,7 @@ int lookup_object (tux_req_t *req, const unsigned int flag)
 		req->status = 403;
 		goto abort;
 	}
-	req->total_file_len = dentry->d_inode->i_size;
+	req->total_file_len = i_size_read(dentry->d_inode);
 out:
 	install_req_dentry(req, dentry, mnt);
 	return 0;
diff --git a/net/tux/main.c b/net/tux/main.c
index 663ce97..a881374 100644
--- a/net/tux/main.c
+++ b/net/tux/main.c
@@ -970,7 +970,7 @@ fetch_missed:
 			return;
 		}
 	}
-	req->total_file_len = req->dentry->d_inode->i_size;
+	req->total_file_len = i_size_read(req->dentry->d_inode);
 	if (!req->output_len)
 		req->output_len = req->total_file_len;
 	if (tux_fetch_file(req, !cachemiss)) {
diff --git a/net/tux/proto_ftp.c b/net/tux/proto_ftp.c
index 2d56416..599e1ff 100644
--- a/net/tux/proto_ftp.c
+++ b/net/tux/proto_ftp.c
@@ -737,7 +737,7 @@ void ftp_get_size (tux_req_t *req, int cachemiss)
 		}
 	}
 	req->in_file->f_pos = 0;
-	len = sprintf(file_size, "213 %Li\r\n", req->dentry->d_inode->i_size);
+	len = sprintf(file_size, "213 %Li\r\n", i_size_read(req->dentry->d_inode));
 	__ftp_send_async_message(req, file_size, 200, len);
 }
 
@@ -1050,7 +1050,7 @@ static char * ftp_print_dir_line (tux_req_t *req, char *tmp, char *d_name, int d
 	memset(tmp, ' ', size);
 	tmp += size;
 
-	tmp += sprintf(tmp, "%8Li", inode->i_size);
+	tmp += sprintf(tmp, "%8Li", i_size_read(inode));
 	*tmp++ = ' ';
 
 	tmp += time_unix2ls(inode->i_mtime.tv_sec, tmp);
diff --git a/net/tux/proto_http.c b/net/tux/proto_http.c
index bb126dd..31cb077 100644
--- a/net/tux/proto_http.c
+++ b/net/tux/proto_http.c
@@ -765,6 +765,7 @@ static int lookup_url (tux_req_t *req, const unsigned int flag)
 	struct vfsmount *mnt = NULL;
 	struct inode *inode;
 	const char *filename;
+	loff_t i_siz;
 
 	/*
 	 * Do not do any etag or last_modified header checking
@@ -846,12 +847,13 @@ repeat_lookup:
 		dentry = NULL;
 		goto repeat_lookup;
 	}
-	if (tux_max_object_size && (inode->i_size > tux_max_object_size)) {
-		TDprintk("too big object, %Ld bytes.\n", inode->i_size);
+	i_siz = i_size_read(inode);
+	if (tux_max_object_size && (i_siz > tux_max_object_size)) {
+		TDprintk("too big object, %Ld bytes.\n", i_siz);
 		req->status = 403;
 		goto abort;
 	}
-	req->total_file_len = inode->i_size;
+	req->total_file_len = i_siz;
 	req->mtime = inode->i_mtime.tv_sec;
 
 	{
@@ -991,9 +993,9 @@ int handle_gzip_req (tux_req_t *req, unsigned int flags)
 	}
 
 	inode = dentry->d_inode;
-	size = inode->i_size;
+	size = i_size_read(inode);
 	orig_inode = req->dentry->d_inode;
-	orig_size = orig_inode->i_size;
+	orig_size = i_size_read(orig_inode);
 
 	if (!tux_permission(inode)
 			&& (size < orig_size)
@@ -2152,7 +2154,7 @@ static char * http_print_dir_line (tux_req_t *req, char *tmp, char *d_name, int
 		COPY_STR("        - ");
 		goto out_size;
 	}
-	size = inode->i_size >> 10;
+	size = i_size_read(inode) >> 10;
 	if (size < 1024) {
 		tmp += sprintf(tmp, "%8Lik ", size);
 		goto out_size;