Re: "EXT3-fs error" after resume from s2ram

From: Tejun Heo
Date: Wed Jul 08 2009 - 11:22:18 EST


Tejun Heo wrote:
> One thing we can do is to make libata remember the native size on
> initial probing and let revalidation consider it. Yeap, that would
> work. Can you please test the attached patch and post full log
> including boot and suspend/resume?

Patch slightly updated. Please test this one.

--
tejun
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 045a486..111c5c9 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1515,6 +1515,7 @@ static int ata_hpa_resize(struct ata_device *dev)

return rc;
}
+ dev->n_native_sectors = native_sectors;

/* nothing to do? */
if (native_sectors <= sectors || !ata_ignore_hpa) {
@@ -4089,6 +4090,7 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
unsigned int readid_flags)
{
u64 n_sectors = dev->n_sectors;
+ u64 n_native_sectors = dev->n_native_sectors;
int rc;

if (!ata_dev_enabled(dev))
@@ -4118,16 +4120,31 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
/* verify n_sectors hasn't changed */
if (dev->class == ATA_DEV_ATA && n_sectors &&
dev->n_sectors != n_sectors) {
- ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
+ ata_dev_printk(dev, KERN_WARNING, "n_sectors mismatch "
"%llu != %llu\n",
(unsigned long long)n_sectors,
(unsigned long long)dev->n_sectors);

- /* restore original n_sectors */
- dev->n_sectors = n_sectors;
-
- rc = -ENODEV;
- goto fail;
+ /*
+ * Something could have caused HPA to be unlocked
+ * involuntarily. If n_native_sectors hasn't changed
+ * and the new size matches it, keep the device.
+ */
+ if (dev->n_native_sectors == n_native_sectors &&
+ dev->n_sectors > n_sectors &&
+ dev->n_sectors == n_native_sectors) {
+ ata_dev_printk(dev, KERN_WARNING,
+ "new n_sectors matches native, probably "
+ "late HPA unlock, continuing\n");
+ dev->n_native_sectors = n_native_sectors;
+ dev->n_sectors = n_sectors;
+ } else {
+ /* restore original n_[native]_sectors */
+ dev->n_native_sectors = n_native_sectors;
+ dev->n_sectors = n_sectors;
+ rc = -ENODEV;
+ goto fail;
+ }
}

return 0;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 3d501db..5fde0a9 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -588,6 +588,7 @@ struct ata_device {
#endif
/* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
u64 n_sectors; /* size of device, if ATA */
+ u64 n_native_sectors; /* native size, if ATA */
unsigned int class; /* ATA_DEV_xxx */
unsigned long unpark_deadline;