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:
Ingo Weinhold 2008-08-10 23:46:00 +00:00
parent 4b7da592ee
commit 77acd7fece
2 changed files with 112 additions and 25 deletions

View File

@ -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);

View File

@ -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 */