/* * invalidate part or all of a page */ static void afs_file_invalidatepage(struct page *page, unsigned long offset) { int ret = 1; _enter("{%lu},%lu", page->index, offset); BUG_ON(!PageLocked(page)); if (PagePrivate(page)) { #ifdef AFS_CACHING_SUPPORT struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); cachefs_uncache_page(vnode->cache,page); #endif /* We release buffers only if the entire page is being * invalidated. * The get_block cached value has been unconditionally * invalidated, so real IO is not possible anymore. */ if (offset == 0) { BUG_ON(!PageLocked(page)); ret = 0; if (!PageWriteback(page)) ret = page->mapping->a_ops->releasepage(page, 0); /* possibly should BUG_ON(!ret); - neilb */ } } _leave(" = %d", ret); } /* end afs_file_invalidatepage() */
/* * release a page and cleanup its private data */ static int afs_file_releasepage(struct page *page, gfp_t gfp_flags) { struct cachefs_page *pageio; _enter("{%lu},%x", page->index, gfp_flags); if (PagePrivate(page)) { #ifdef AFS_CACHING_SUPPORT struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); cachefs_uncache_page(vnode->cache, page); #endif pageio = (struct cachefs_page *) page_private(page); set_page_private(page, 0); ClearPagePrivate(page); kfree(pageio); } _leave(" = 0"); return 0; } /* end afs_file_releasepage() */
/* * AFS read page from file (or symlink) */ static int afs_file_readpage(struct file *file, struct page *page) { struct afs_rxfs_fetch_descriptor desc; #ifdef AFS_CACHING_SUPPORT struct cachefs_page *pageio; #endif struct afs_vnode *vnode; struct inode *inode; int ret; inode = page->mapping->host; _enter("{%lu},{%lu}", inode->i_ino, page->index); vnode = AFS_FS_I(inode); BUG_ON(!PageLocked(page)); ret = -ESTALE; if (vnode->flags & AFS_VNODE_DELETED) goto error; #ifdef AFS_CACHING_SUPPORT ret = cachefs_page_get_private(page, &pageio, GFP_NOIO); if (ret < 0) goto error; /* is it cached? */ ret = cachefs_read_or_alloc_page(vnode->cache, page, afs_file_readpage_read_complete, NULL, GFP_KERNEL); #else ret = -ENOBUFS; #endif switch (ret) { /* read BIO submitted and wb-journal entry found */ case 1: BUG(); // TODO - handle wb-journal match /* read BIO submitted (page in cache) */ case 0: break; /* no page available in cache */ case -ENOBUFS: case -ENODATA: default: desc.fid = vnode->fid; desc.offset = page->index << PAGE_CACHE_SHIFT; desc.size = min((size_t) (inode->i_size - desc.offset), (size_t) PAGE_SIZE); desc.buffer = kmap(page); clear_page(desc.buffer); /* read the contents of the file from the server into the * page */ ret = afs_vnode_fetch_data(vnode, &desc); kunmap(page); if (ret < 0) { if (ret==-ENOENT) { _debug("got NOENT from server" " - marking file deleted and stale"); vnode->flags |= AFS_VNODE_DELETED; ret = -ESTALE; } #ifdef AFS_CACHING_SUPPORT cachefs_uncache_page(vnode->cache, page); #endif goto error; } SetPageUptodate(page); #ifdef AFS_CACHING_SUPPORT if (cachefs_write_page(vnode->cache, page, afs_file_readpage_write_complete, NULL, GFP_KERNEL) != 0 ) { cachefs_uncache_page(vnode->cache, page); unlock_page(page); } #else unlock_page(page); #endif } _leave(" = 0"); return 0; error: SetPageError(page); unlock_page(page); _leave(" = %d", ret); return ret; } /* end afs_file_readpage() */
/* * AFS read page from file, directory or symlink */ static int afs_readpage(struct file *file, struct page *page) { struct afs_vnode *vnode; struct inode *inode; struct key *key; size_t len; off_t offset; int ret; inode = page->mapping->host; ASSERT(file != NULL); key = file->private_data; ASSERT(key != NULL); _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); vnode = AFS_FS_I(inode); BUG_ON(!PageLocked(page)); ret = -ESTALE; if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) goto error; #ifdef AFS_CACHING_SUPPORT /* is it cached? */ ret = cachefs_read_or_alloc_page(vnode->cache, page, afs_file_readpage_read_complete, NULL, GFP_KERNEL); #else ret = -ENOBUFS; #endif switch (ret) { /* read BIO submitted and wb-journal entry found */ case 1: BUG(); // TODO - handle wb-journal match /* read BIO submitted (page in cache) */ case 0: break; /* no page available in cache */ case -ENOBUFS: case -ENODATA: default: offset = page->index << PAGE_CACHE_SHIFT; len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); /* read the contents of the file from the server into the * page */ ret = afs_vnode_fetch_data(vnode, key, offset, len, page); if (ret < 0) { if (ret == -ENOENT) { _debug("got NOENT from server" " - marking file deleted and stale"); set_bit(AFS_VNODE_DELETED, &vnode->flags); ret = -ESTALE; } #ifdef AFS_CACHING_SUPPORT cachefs_uncache_page(vnode->cache, page); #endif goto error; } SetPageUptodate(page); #ifdef AFS_CACHING_SUPPORT if (cachefs_write_page(vnode->cache, page, afs_file_readpage_write_complete, NULL, GFP_KERNEL) != 0 ) { cachefs_uncache_page(vnode->cache, page); unlock_page(page); } #else unlock_page(page); #endif } _leave(" = 0"); return 0; error: SetPageError(page); unlock_page(page); _leave(" = %d", ret); return ret; }