Patch by Zhao Shuai with some changes by myself:
* Added functions swap_free_page_swap_space(), swap_available_pages(), and swap_total_swap_pages(). They will be used by the page daemon code. * Free allocated swap space in the VMAnonymousCache destructor. * Write(): First free swap space assigned to the pages to be written (was leaked before) and update fAllocatedSwapSize upfront. Both is now done with the cache locked, as it should be. * Fixes several instance where the cache offset in bytes was used instead of in pages. * Print the correct error when _kern_write_stat() fails. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26926 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
4b7da592ee
commit
77acd7fece
@ -141,6 +141,18 @@ static mutex sAvailSwapSpaceLock;
|
|||||||
|
|
||||||
VMAnonymousCache::~VMAnonymousCache()
|
VMAnonymousCache::~VMAnonymousCache()
|
||||||
{
|
{
|
||||||
|
// free allocated swap space and swap block
|
||||||
|
for (off_t offset = virtual_base, toFree = fAllocatedSwapSize;
|
||||||
|
offset < virtual_end && toFree > 0; offset += B_PAGE_SIZE) {
|
||||||
|
swap_addr_t pageIndex = _SwapBlockGetAddress(offset >> PAGE_SHIFT);
|
||||||
|
if (pageIndex == SWAP_PAGE_NONE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
swap_page_dealloc(pageIndex, 1);
|
||||||
|
_SwapBlockFree(offset >> PAGE_SHIFT);
|
||||||
|
toFree -= B_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
swap_space_unreserve(fCommittedSwapSize);
|
swap_space_unreserve(fCommittedSwapSize);
|
||||||
vm_unreserve_memory(committed_size);
|
vm_unreserve_memory(committed_size);
|
||||||
}
|
}
|
||||||
@ -234,10 +246,24 @@ status_t
|
|||||||
VMAnonymousCache::Write(off_t offset, const iovec *vecs, size_t count,
|
VMAnonymousCache::Write(off_t offset, const iovec *vecs, size_t count,
|
||||||
size_t *_numBytes)
|
size_t *_numBytes)
|
||||||
{
|
{
|
||||||
if (fAllocatedSwapSize + count * PAGE_SIZE > fCommittedSwapSize)
|
offset >>= PAGE_SHIFT;
|
||||||
|
|
||||||
|
Lock();
|
||||||
|
for (uint32 i = 0; i < count; i++) {
|
||||||
|
swap_addr_t pageIndex = _SwapBlockGetAddress(offset + i);
|
||||||
|
if (pageIndex != SWAP_PAGE_NONE) {
|
||||||
|
swap_page_dealloc(pageIndex, 1);
|
||||||
|
_SwapBlockFree(offset + i);
|
||||||
|
fAllocatedSwapSize -= B_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fAllocatedSwapSize + count * B_PAGE_SIZE > fCommittedSwapSize)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
offset >>= PAGE_SHIFT;
|
fAllocatedSwapSize += count * B_PAGE_SIZE;
|
||||||
|
Unlock();
|
||||||
|
|
||||||
uint32 n = count;
|
uint32 n = count;
|
||||||
for (uint32 i = 0; i < count; i += n) {
|
for (uint32 i = 0; i < count; i += n) {
|
||||||
swap_addr_t pageIndex;
|
swap_addr_t pageIndex;
|
||||||
@ -248,24 +274,28 @@ VMAnonymousCache::Write(off_t offset, const iovec *vecs, size_t count,
|
|||||||
if (pageIndex == SWAP_PAGE_NONE)
|
if (pageIndex == SWAP_PAGE_NONE)
|
||||||
panic("can't allocate swap space\n");
|
panic("can't allocate swap space\n");
|
||||||
|
|
||||||
fAllocatedSwapSize += n * PAGE_SIZE;
|
|
||||||
|
|
||||||
for (uint32 j = 0; j < n; j++)
|
|
||||||
_SwapBlockBuild(offset + i + j, pageIndex + j);
|
|
||||||
|
|
||||||
swap_file *swapFile = find_swap_file(pageIndex);
|
swap_file *swapFile = find_swap_file(pageIndex);
|
||||||
if (swapFile == NULL) {
|
if (swapFile == NULL) {
|
||||||
panic("can't find swap file for page index %ld\n", pageIndex);
|
panic("can't find swap file for page index %ld\n", pageIndex);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t pos = (pageIndex - swapFile->first_page) * PAGE_SIZE;
|
off_t pos = (pageIndex - swapFile->first_page) * B_PAGE_SIZE;
|
||||||
status_t status = vfs_write_pages(swapFile->vnode, NULL, pos, vecs + i,
|
status_t status = vfs_write_pages(swapFile->vnode, NULL, pos, vecs + i,
|
||||||
n, 0, _numBytes);
|
n, 0, _numBytes);
|
||||||
if (status != B_OK)
|
if (status != B_OK) {
|
||||||
|
Lock();
|
||||||
|
fAllocatedSwapSize -= n * B_PAGE_SIZE;
|
||||||
|
Unlock();
|
||||||
|
|
||||||
|
swap_page_dealloc(pageIndex, n);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint32 j = 0; j < n; j++)
|
||||||
|
_SwapBlockBuild(offset + i + j, pageIndex + j);
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,29 +362,32 @@ VMAnonymousCache::MergeStore(VMCache* _source)
|
|||||||
// TODO: iterate over swap blocks
|
// TODO: iterate over swap blocks
|
||||||
for (off_t offset = source->virtual_base; offset < source->virtual_end;
|
for (off_t offset = source->virtual_base; offset < source->virtual_end;
|
||||||
offset += PAGE_SIZE) {
|
offset += PAGE_SIZE) {
|
||||||
swap_addr_t sourceSwapIndex = source->_SwapBlockGetAddress(offset);
|
off_t cacheOffset = offset >> PAGE_SHIFT;
|
||||||
|
swap_addr_t sourceSwapIndex = source->_SwapBlockGetAddress(cacheOffset);
|
||||||
|
|
||||||
if (sourceSwapIndex == SWAP_PAGE_NONE)
|
if (sourceSwapIndex == SWAP_PAGE_NONE)
|
||||||
// this page is not swapped out
|
// this page is not swapped out
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (LookupPage(offset))
|
if (LookupPage(offset)) {
|
||||||
// this page is shadowed and we can find it in the new cache,
|
// this page is shadowed and we can find it in the new cache,
|
||||||
// free the swap space
|
// free the swap space
|
||||||
swap_page_dealloc(sourceSwapIndex, 1);
|
swap_page_dealloc(sourceSwapIndex, 1);
|
||||||
else {
|
} else {
|
||||||
swap_addr_t swapIndex = _SwapBlockGetAddress(offset);
|
swap_addr_t swapIndex = _SwapBlockGetAddress(cacheOffset);
|
||||||
|
|
||||||
if (swapIndex == SWAP_PAGE_NONE) {
|
if (swapIndex == SWAP_PAGE_NONE) {
|
||||||
// the page is not shadowed,
|
// the page is not shadowed,
|
||||||
// assign the swap address to the new cache
|
// assign the swap address to the new cache
|
||||||
_SwapBlockBuild(offset, sourceSwapIndex);
|
_SwapBlockBuild(cacheOffset, sourceSwapIndex);
|
||||||
|
fAllocatedSwapSize += B_PAGE_SIZE;
|
||||||
} else {
|
} else {
|
||||||
// the page is shadowed and is also swapped out
|
// the page is shadowed and is also swapped out
|
||||||
swap_page_dealloc(sourceSwapIndex, 1);
|
swap_page_dealloc(sourceSwapIndex, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
source->_SwapBlockFree(offset);
|
source->fAllocatedSwapSize -= B_PAGE_SIZE;
|
||||||
|
source->_SwapBlockFree(cacheOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,7 +433,6 @@ VMAnonymousCache::_SwapBlockFree(off_t cacheOffset)
|
|||||||
mutex_lock(&sSwapHashLock);
|
mutex_lock(&sSwapHashLock);
|
||||||
|
|
||||||
swap_hash_key key = { this, cacheOffset };
|
swap_hash_key key = { this, cacheOffset };
|
||||||
|
|
||||||
swap_block *swap = sSwapHashTable.Lookup(key);
|
swap_block *swap = sSwapHashTable.Lookup(key);
|
||||||
if (swap != NULL) {
|
if (swap != NULL) {
|
||||||
swap_addr_t pageIndex = swap->swap_pages[cacheOffset & SWAP_BLOCK_MASK];
|
swap_addr_t pageIndex = swap->swap_pages[cacheOffset & SWAP_BLOCK_MASK];
|
||||||
@ -504,6 +536,52 @@ find_swap_file(swap_addr_t pageIndex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// used by page daemon to free swap space
|
||||||
|
bool
|
||||||
|
swap_free_page_swap_space(vm_page *page)
|
||||||
|
{
|
||||||
|
VMAnonymousCache *cache = dynamic_cast<VMAnonymousCache *>(page->cache);
|
||||||
|
if (cache == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
swap_addr_t pageIndex = cache->_SwapBlockGetAddress(page->cache_offset);
|
||||||
|
if (pageIndex == SWAP_PAGE_NONE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
swap_page_dealloc(pageIndex, 1);
|
||||||
|
cache->fAllocatedSwapSize -= B_PAGE_SIZE;
|
||||||
|
cache->_SwapBlockFree(page->cache_offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
swap_available_pages()
|
||||||
|
{
|
||||||
|
mutex_lock(&sAvailSwapSpaceLock);
|
||||||
|
uint32 avail = sAvailSwapSpace >> PAGE_SHIFT;
|
||||||
|
mutex_unlock(&sAvailSwapSpaceLock);
|
||||||
|
|
||||||
|
return avail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
swap_total_swap_pages()
|
||||||
|
{
|
||||||
|
mutex_lock(&sSwapFileListLock);
|
||||||
|
|
||||||
|
uint32 totalSwapPages = 0;
|
||||||
|
for (SwapFileList::Iterator it = sSwapFileList.GetIterator();
|
||||||
|
swap_file *swapFile = it.Next();)
|
||||||
|
totalSwapPages += swapFile->last_page - swapFile->first_page;
|
||||||
|
|
||||||
|
mutex_unlock(&sSwapFileListLock);
|
||||||
|
|
||||||
|
return totalSwapPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static swap_addr_t
|
static swap_addr_t
|
||||||
swap_page_alloc(uint32 npages)
|
swap_page_alloc(uint32 npages)
|
||||||
{
|
{
|
||||||
@ -567,6 +645,9 @@ swap_page_alloc(uint32 npages)
|
|||||||
static void
|
static void
|
||||||
swap_page_dealloc(swap_addr_t pageIndex, uint32 npages)
|
swap_page_dealloc(swap_addr_t pageIndex, uint32 npages)
|
||||||
{
|
{
|
||||||
|
if (pageIndex == SWAP_PAGE_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
mutex_lock(&sSwapFileListLock);
|
mutex_lock(&sSwapFileListLock);
|
||||||
swap_file *swapFile = find_swap_file(pageIndex);
|
swap_file *swapFile = find_swap_file(pageIndex);
|
||||||
|
|
||||||
@ -772,10 +853,11 @@ swap_init_post_modules()
|
|||||||
|
|
||||||
struct stat stat;
|
struct stat stat;
|
||||||
stat.st_size = size;
|
stat.st_size = size;
|
||||||
if (_kern_write_stat(fd, NULL, false, &stat, sizeof(struct stat),
|
status_t error = _kern_write_stat(fd, NULL, false, &stat,
|
||||||
B_STAT_SIZE | B_STAT_SIZE_INSECURE) != B_OK) {
|
sizeof(struct stat), B_STAT_SIZE | B_STAT_SIZE_INSECURE);
|
||||||
|
if (error != B_OK) {
|
||||||
dprintf("Failed to resize /var/swap to %lld bytes: %s\n", size,
|
dprintf("Failed to resize /var/swap to %lld bytes: %s\n", size,
|
||||||
strerror(errno));
|
strerror(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -17,6 +17,15 @@
|
|||||||
typedef page_num_t swap_addr_t;
|
typedef page_num_t swap_addr_t;
|
||||||
struct swap_block;
|
struct swap_block;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void swap_init(void);
|
||||||
|
void swap_init_post_modules(void);
|
||||||
|
bool swap_free_page_swap_space(vm_page *page);
|
||||||
|
uint32 swap_available_pages(void);
|
||||||
|
uint32 swap_total_swap_pages(void);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class VMAnonymousCache : public VMCache {
|
class VMAnonymousCache : public VMCache {
|
||||||
public:
|
public:
|
||||||
virtual ~VMAnonymousCache();
|
virtual ~VMAnonymousCache();
|
||||||
@ -43,6 +52,8 @@ private:
|
|||||||
status_t _Commit(off_t size);
|
status_t _Commit(off_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend bool swap_free_page_swap_space(vm_page *page);
|
||||||
|
|
||||||
bool fCanOvercommit;
|
bool fCanOvercommit;
|
||||||
bool fHasPrecommitted;
|
bool fHasPrecommitted;
|
||||||
uint8 fPrecommittedPages;
|
uint8 fPrecommittedPages;
|
||||||
@ -51,12 +62,6 @@ private:
|
|||||||
off_t fAllocatedSwapSize;
|
off_t fAllocatedSwapSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
void swap_init(void);
|
|
||||||
void swap_init_post_modules();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // ENABLE_SWAP_SUPPORT
|
#endif // ENABLE_SWAP_SUPPORT
|
||||||
|
|
||||||
#endif /* _KERNEL_VM_STORE_ANONYMOUS_H */
|
#endif /* _KERNEL_VM_STORE_ANONYMOUS_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user