[PATCH] tmpfs surplus page miscounted

From: Hugh Dickins
Date: Sun May 30 2004 - 11:13:48 EST


Bjorn Wesen reports BUG_ON(inode->i_blocks) after sendfile or loop has
primed page cache with a tmpfs page, but the subsequent shmem_readpage
or shmem_prepare_write failed because filesystem max size was exceeded:
the surplus page has not been accounted, yet truncation assumes it has.

The obvious fix, to check Page_Uptodate in shmem_removepage, does not
work: because it has anyway been cleared by the time that is called.
We could rearrange, but it might be safer to avoid subtle dependency,
and just fix this up within shmem.c: using the PageError flag instead.

This is not an issue for 2.6, which uses shmem_recalc_inode instead of
2.4's removepage method, and so is ready for nrpages to drift a little.

Hugh

--- 2.4.27-pre3/mm/shmem.c 2003-11-28 18:26:21.000000000 +0000
+++ linux/mm/shmem.c 2004-05-30 16:20:49.374589600 +0100
@@ -86,7 +86,7 @@ static void shmem_free_block(struct inod

static void shmem_removepage(struct page *page)
{
- if (!PageLaunder(page))
+ if (!PageLaunder(page) && !PageError(page))
shmem_free_block(page->mapping->host);
}

@@ -626,8 +626,11 @@ static int shmem_getpage(struct inode *i
swp_entry_t swap;
int error = 0;

- if (idx >= SHMEM_MAX_INDEX)
- return -EFBIG;
+ if (idx >= SHMEM_MAX_INDEX) {
+ error = -EFBIG;
+ goto failed;
+ }
+
/*
* Normally, filepage is NULL on entry, and either found
* uptodate immediately, or allocated and zeroed, or read
@@ -781,18 +784,24 @@ repeat:
}
done:
if (!*pagep) {
- if (filepage) {
+ if (filepage)
UnlockPage(filepage);
- *pagep = filepage;
- } else
- *pagep = ZERO_PAGE(0);
+ else
+ filepage = ZERO_PAGE(0);
+ *pagep = filepage;
}
+ if (PageError(filepage))
+ ClearPageError(filepage);
return 0;

failed:
- if (*pagep != filepage) {
- UnlockPage(filepage);
- page_cache_release(filepage);
+ if (filepage) {
+ if (*pagep == filepage)
+ SetPageError(filepage);
+ else {
+ UnlockPage(filepage);
+ page_cache_release(filepage);
+ }
}
return error;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/