diff -r 194770c95587 drivers/scsi/scsi_dif.c --- a/drivers/scsi/scsi_dif.c Mon May 26 23:40:20 2008 -0400 +++ b/drivers/scsi/scsi_dif.c Sun Jun 01 14:49:24 2008 -0400 @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include @@ -62,7 +64,11 @@ for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { sdt->guard_tag = fn(buf, bix->sector_size); sdt->ref_tag = cpu_to_be32(sector & 0xffffffff); - sdt->app_tag = 0; + + if (sdt->guard_tag == 0xffff) + sdt->app_tag = 0xdead; + else + sdt->app_tag = 0; buf += bix->sector_size; sector++; @@ -516,6 +522,44 @@ } } +void bio_dump(struct bio *bio, const char *pfx) +{ + struct bip *bip = bio->bi_integrity; + struct bio_vec *bv; + unsigned int i; + sector_t ssec = bio->bi_sector; + + printk(KERN_ERR "%s: bio %p, dev %s, %s %u bytes @ sector %lu\n", + pfx, + bio, + bio->bi_bdev->bd_disk->disk_name, + bio_data_dir(bio) == WRITE ? "wr" : "rd", + bio_sectors(bio) << 9, + bio->bi_sector); + + bio_for_each_segment(bv, bio, i) { + printk(KERN_ERR " bv%02u(%p, %u, %u), sector %lu\n", i, + bv->bv_page, bv->bv_offset, bv->bv_len, + ssec); + ssec += bv->bv_len >> 9; + } + + printk(KERN_ERR "%s: bip %p, size %u, sector %lu, idx %u, vcnt %u\n", + pfx, + bip, + bip->bip_size, + bip->bip_sector, + bip->bip_idx, + bip->bip_vcnt); + + bip_for_each_vec(bv, bip, i) { + printk(KERN_ERR " iv%02u(%p, %u, %u)\n", i, + bv->bv_page, bv->bv_offset, bv->bv_len); + } + + printk("\n"); +} + int scsi_dif_check(struct scsi_cmnd * SCpnt, sector_t start_sec) { int i, j, ret; @@ -526,6 +570,7 @@ sector_t sector = start_sec; int ppage_offset; unsigned short csum; + struct bio *bio; if (((SCpnt->cmnd[1] >> 5) & 7) != 1) { printk(KERN_WARNING "scsi_dif_check: WRPROTECT != 1\n"); @@ -537,9 +582,12 @@ paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset; ppage_offset = 0; + ret = 0; /* For each data page */ scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { + BUG_ON(page_check_wrprotect(sg_page(dsgl))); + daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset; /* For each sector-sized chunk in data page */ @@ -563,12 +611,13 @@ if (sdt->guard_tag != csum) { printk(KERN_ERR "%s: GUARD check failed on sector %lu " \ - "rcvd 0x%04x, calculated 0x%04x\n", - __func__, sector, - be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); + "rcvd 0x%04x\n", + __func__, sector, be16_to_cpu(sdt->guard_tag)); + printk(KERN_ERR "\tcalculated 0x%04x, app 0x%04x, ref %10u\n", + be16_to_cpu(csum), sdt->app_tag, be32_to_cpu(sdt->ref_tag)); ret = 0x01; dump_sector(daddr, 512); - goto out; +// goto out; } if (be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { @@ -577,7 +626,7 @@ __func__, sector); ret = 0x03; dump_sector(daddr, 512); - goto out; +// goto out; } sector++; @@ -585,16 +634,26 @@ ppage_offset += sizeof(struct scsi_dif_tuple); } + ClearPageIntegrity(sg_page(dsgl)); kunmap_atomic(sg_page(dsgl), KM_IRQ0); } +// kunmap_atomic(sg_page(psgl), KM_IRQ1); + +// return 0; + +out: +// kunmap_atomic(sg_page(dsgl), KM_IRQ0); kunmap_atomic(sg_page(psgl), KM_IRQ1); - return 0; + if (ret) { + __rq_for_each_bio(bio, SCpnt->request) { + bio_dump(bio, __func__); + } -out: - kunmap_atomic(sg_page(dsgl), KM_IRQ0); - kunmap_atomic(sg_page(psgl), KM_IRQ1); + BUG(); + } + return ret; } EXPORT_SYMBOL(scsi_dif_check); diff -r 194770c95587 fs/bio-integrity.c --- a/fs/bio-integrity.c Mon May 26 23:40:20 2008 -0400 +++ b/fs/bio-integrity.c Sun Jun 01 14:49:24 2008 -0400 @@ -24,6 +24,7 @@ #include #include #include +#include static struct kmem_cache *bio_integrity_slab __read_mostly; static struct workqueue_struct *kintegrityd_wq; @@ -286,14 +287,17 @@ struct blk_integrity_exchg bix; struct bio_vec *bv; sector_t sector = bio->bi_sector; - unsigned int i, sectors, total; + unsigned int i, sectors, total, secs; void *prot_buf = bio->bi_integrity->bip_buf; - total = 0; + total = secs = 0; bix.disk_name = bio->bi_bdev->bd_disk->disk_name; bix.sector_size = bi->sector_size; bio_for_each_segment(bv, bio, i) { + BUG_ON(page_check_wrprotect(bv->bv_page)); + SetPageIntegrity(bv->bv_page); + bix.data_buf = kmap_atomic(bv->bv_page, KM_USER0) + bv->bv_offset; bix.data_size = bv->bv_len; @@ -304,12 +308,15 @@ sectors = bv->bv_len / bi->sector_size; sector += sectors; + secs += sectors; prot_buf += sectors * bi->tuple_size; total += sectors * bi->tuple_size; BUG_ON(total > bio->bi_integrity->bip_size); kunmap_atomic(bv->bv_page, KM_USER0); } + + BUG_ON(secs != bio_sectors(bio)); } /** @@ -365,6 +372,9 @@ bip->bip_buf = buf; bip->bip_size = len; bip->bip_sector = bio->bi_sector; + memset(buf, 0xfc, len); + + BUG_ON(bio_sectors(bio) != (len >> 3)); /* Map it */ offset = offset_in_page(buf); diff -r 194770c95587 fs/buffer.c --- a/fs/buffer.c Mon May 26 23:40:20 2008 -0400 +++ b/fs/buffer.c Sun Jun 01 14:49:24 2008 -0400 @@ -2442,6 +2442,8 @@ *pagep = page; *fsdata = NULL; + wait_on_page_volatile(page, __func__, 1); + if (page_has_buffers(page)) { unlock_page(page); page_cache_release(page); @@ -2672,6 +2674,8 @@ if (!page) goto out; + wait_on_page_volatile(page, __func__, 1); + if (page_has_buffers(page)) { has_buffers: unlock_page(page); @@ -2748,7 +2752,9 @@ if (!page) goto out; - if (!page_has_buffers(page)) + if (page_has_buffers(page)) + wait_on_page_volatile(page, __func__, 1); + else create_empty_buffers(page, blocksize, 0); /* Find the buffer that contains "offset" */ diff -r 194770c95587 fs/ext3/inode.c --- a/fs/ext3/inode.c Mon May 26 23:40:20 2008 -0400 +++ b/fs/ext3/inode.c Sun Jun 01 14:49:25 2008 -0400 @@ -1157,6 +1157,8 @@ return -ENOMEM; *pagep = page; + wait_on_page_volatile(page, __func__, 0); + handle = ext3_journal_start(inode, needed_blocks); if (IS_ERR(handle)) { unlock_page(page); @@ -2317,6 +2319,8 @@ inode->i_size >> PAGE_CACHE_SHIFT); if (!page) return; + + wait_on_page_volatile(page, __func__, 1); } handle = start_transaction(inode); diff -r 194770c95587 include/linux/page-flags.h --- a/include/linux/page-flags.h Mon May 26 23:40:20 2008 -0400 +++ b/include/linux/page-flags.h Sun Jun 01 14:49:25 2008 -0400 @@ -96,6 +96,7 @@ #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR PG_uncached, /* Page has been mapped as uncached */ #endif + PG_integrity, __NR_PAGEFLAGS }; @@ -194,6 +195,8 @@ #else PAGEFLAG_FALSE(Uncached) #endif + +PAGEFLAG(Integrity, integrity) static inline int PageUptodate(struct page *page) { diff -r 194770c95587 include/linux/pagemap.h --- a/include/linux/pagemap.h Mon May 26 23:40:20 2008 -0400 +++ b/include/linux/pagemap.h Sun Jun 01 14:49:25 2008 -0400 @@ -223,6 +223,19 @@ wait_on_page_bit(page, PG_writeback); } +static inline void wait_on_page_volatile(struct page *page, const char *func, int bug) +{ + if (!PageWriteback(page) && !PageIntegrity(page)) + return; + + if (bug) { + printk(KERN_ERR "%s: waiting for %p\n", func, page); + wait_on_page_writeback(page); + printk(KERN_ERR "%s: got %p\n", func, page); + BUG(); + } +} + extern void end_page_writeback(struct page *page); /* diff -r 194770c95587 include/linux/rmap.h --- a/include/linux/rmap.h Mon May 26 23:40:20 2008 -0400 +++ b/include/linux/rmap.h Sun Jun 01 14:49:25 2008 -0400 @@ -75,6 +75,9 @@ void page_add_file_rmap(struct page *); void page_remove_rmap(struct page *, struct vm_area_struct *); + +extern int page_check_wrprotect(struct page *); + #ifdef CONFIG_DEBUG_VM void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address); #else diff -r 194770c95587 mm/filemap.c --- a/mm/filemap.c Mon May 26 23:40:20 2008 -0400 +++ b/mm/filemap.c Sun Jun 01 14:49:25 2008 -0400 @@ -667,6 +667,15 @@ read_lock_irq(&mapping->tree_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page) { +#if 0 + if (PageWriteback(page)) { + read_unlock_irq(&mapping->tree_lock); + printk(KERN_ERR "%s: Waiting on %p\n", __func__, page); + wait_on_page_writeback(page); + read_lock_irq(&mapping->tree_lock); + } +#endif + page_cache_get(page); if (TestSetPageLocked(page)) { read_unlock_irq(&mapping->tree_lock); @@ -1948,6 +1957,8 @@ goto again; } + wait_on_page_volatile(page, __func__, 1); + ret = aops->prepare_write(file, page, offset, offset+len); if (ret) { unlock_page(page); diff -r 194770c95587 mm/rmap.c --- a/mm/rmap.c Mon May 26 23:40:20 2008 -0400 +++ b/mm/rmap.c Sun Jun 01 14:49:25 2008 -0400 @@ -508,6 +508,55 @@ } EXPORT_SYMBOL_GPL(page_mkclean); +int page_check_wrprotect(struct page *page) +{ + struct address_space *mapping; + struct mm_struct *mm; + struct vm_area_struct *vma; + struct prio_tree_iter iter; + pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); + unsigned long address; + pte_t *pte; + spinlock_t *ptl; + int ret = 0; + + if (!page_mapped(page)) + return 0; + + if (PageAnon(page)) + return 0; + + mapping = page_mapping(page); + + spin_lock(&mapping->i_mmap_lock); + vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { + mm = vma->vm_mm; + address = vma_address(page, vma); + + if (address == -EFAULT) + goto out; + + pte = page_check_address(page, mm, address, &ptl); + if (!pte) { + pte_unmap_unlock(pte, ptl); + goto out; + } + + if (pte_write(*pte)) { + printk(KERN_ERR "%s: page %p writable\n", __func__, page); + ret = -1; + } + + pte_unmap_unlock(pte, ptl); + } + +out: + spin_unlock(&mapping->i_mmap_lock); + + return ret; +} +EXPORT_SYMBOL(page_check_wrprotect); + /** * __page_set_anon_rmap - setup new anonymous rmap * @page: the page to add the mapping to