*
* No one can dirty the extent until we've finished our work and they can
* enqueue another lock. The DLM protects us from ll_file_read/write here,
- * but other kernel actors could have pages locked. */
+ * but other kernel actors could have pages locked.
+ *
+ * Called with the DLM lock held. */
void ll_pgcache_remove_extent(struct inode *inode, struct lov_stripe_md *lsm,
struct ldlm_lock *lock, __u32 stripe)
{
- struct ldlm_extent *extent = &lock->l_policy_data.l_extent;
+ ldlm_policy_data_t tmpex;
unsigned long start, end, count, skip, i, j;
struct page *page;
- int rc, discard = lock->l_flags & LDLM_FL_DISCARD_DATA;
+ int rc, rc2, discard = lock->l_flags & LDLM_FL_DISCARD_DATA;
+ struct lustre_handle lockh;
ENTRY;
- CDEBUG(D_INODE, "obdo %lu inode %p ["LPU64"->"LPU64"] size: %llu\n",
- inode->i_ino, inode, extent->start, extent->end, inode->i_size);
+ memcpy(&tmpex, &lock->l_policy_data, sizeof(tmpex));
+ CDEBUG(D_INODE|D_PAGE, "inode %lu(%p) ["LPU64"->"LPU64"] size: %llu\n",
+ inode->i_ino, inode, tmpex.l_extent.start, tmpex.l_extent.end,
+ inode->i_size);
/* our locks are page granular thanks to osc_enqueue, we invalidate the
* whole page. */
- LASSERT((extent->start & ~PAGE_CACHE_MASK) == 0);
- LASSERT(((extent->end+1) & ~PAGE_CACHE_MASK) == 0);
+ LASSERT((tmpex.l_extent.start & ~PAGE_CACHE_MASK) == 0);
+ LASSERT(((tmpex.l_extent.end + 1) & ~PAGE_CACHE_MASK) == 0);
- start = extent->start >> PAGE_CACHE_SHIFT;
count = ~0;
skip = 0;
- end = (extent->end >> PAGE_CACHE_SHIFT) + 1;
- if ((end << PAGE_CACHE_SHIFT) < extent->end)
- end = ~0;
+ start = tmpex.l_extent.start >> PAGE_CACHE_SHIFT;
+ end = tmpex.l_extent.end >> PAGE_CACHE_SHIFT;
if (lsm->lsm_stripe_count > 1) {
count = lsm->lsm_stripe_size >> PAGE_CACHE_SHIFT;
skip = (lsm->lsm_stripe_count - 1) * count;
- start += (start/count * skip) + (stripe * count);
+ start += start/count * skip + stripe * count;
if (end != ~0)
- end += (end/count * skip) + (stripe * count);
- }
+ end += end/count * skip + stripe * count;
+ }
+ if (end < tmpex.l_extent.end >> PAGE_CACHE_SHIFT)
+ end = ~0;
i = (inode->i_size + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
if (i < end)
end = i;
- CDEBUG(D_INODE, "walking page indices start: %lu j: %lu count: %lu "
- "skip: %lu end: %lu%s\n", start, start % count, count, skip, end,
- discard ? " (DISCARDING)" : "");
+ CDEBUG(D_INODE|D_PAGE, "walking page indices start: %lu j: %lu "
+ "count: %lu skip: %lu end: %lu%s\n", start, start % count,
+ count, skip, end, discard ? " (DISCARDING)" : "");
/* this is the simplistic implementation of page eviction at
* cancelation. It is careful to get races with other page
* lockers handled correctly. fixes from bug 20 will make it
* more efficient by associating locks with pages and with
* batching writeback under the lock explicitly. */
- for (i = start, j = start % count ; ; j++, i++) {
- if (j == count) {
- i += skip;
- j = 0;
- }
- if (i >= end)
- break;
+ for (i = start, j = start % count ; i <= end;
+ j++, i++, tmpex.l_extent.start += PAGE_CACHE_SIZE) {
+ LASSERTF(tmpex.l_extent.start< lock->l_policy_data.l_extent.end,
+ LPU64" >= "LPU64" start %lu i %lu end %lu\n",
+ tmpex.l_extent.start, lock->l_policy_data.l_extent.end,
+ start, i, end);
ll_pgcache_lock(inode->i_mapping);
if (list_empty(&inode->i_mapping->dirty_pages) &&
list_empty(&inode->i_mapping->clean_pages) &&
list_empty(&inode->i_mapping->locked_pages)) {
- CDEBUG(D_INODE, "nothing left\n");
+ CDEBUG(D_INODE|D_PAGE, "nothing left\n");
ll_pgcache_unlock(inode->i_mapping);
break;
}
page = find_get_page(inode->i_mapping, i);
if (page == NULL)
- continue;
- LL_CDEBUG_PAGE(page, "locking page\n");
+ goto next_index;
+ LL_CDEBUG_PAGE(D_PAGE, page, "locking page\n");
lock_page(page);
/* page->mapping to check with racing against teardown */
if (page->mapping && PageDirty(page) && !discard) {
ClearPageDirty(page);
- LL_CDEBUG_PAGE(page, "found dirty\n");
+ LL_CDEBUG_PAGE(D_PAGE, page, "found dirty\n");
ll_pgcache_lock(inode->i_mapping);
list_del(&page->list);
list_add(&page->list, &inode->i_mapping->locked_pages);
lock_page(page);
}
- /* checking again to account for writeback's lock_page() */
- if (page->mapping != NULL) {
- LL_CDEBUG_PAGE(page, "truncating\n");
+ tmpex.l_extent.end = tmpex.l_extent.start + PAGE_CACHE_SIZE - 1;
+ /* check to see if another DLM lock covers this page */
+ rc2 = ldlm_lock_match(lock->l_resource->lr_namespace,
+ LDLM_FL_BLOCK_GRANTED|LDLM_FL_CBPENDING |
+ LDLM_FL_TEST_LOCK,
+ &lock->l_resource->lr_name, LDLM_EXTENT,
+ &tmpex, LCK_PR | LCK_PW, &lockh);
+ if (rc2 == 0 && page->mapping != NULL) {
+ // checking again to account for writeback's lock_page()
+ LL_CDEBUG_PAGE(D_PAGE, page, "truncating\n");
ll_truncate_complete_page(page);
}
unlock_page(page);
page_cache_release(page);
+
+ next_index:
+ if (j == count) {
+ i += skip;
+ j = 0;
+ }
}
EXIT;
}
CERROR("ldlm_cli_cancel failed: %d\n", rc);
break;
case LDLM_CB_CANCELING: {
- struct inode *inode = ll_inode_from_lock(lock);
+ struct inode *inode;
struct ll_inode_info *lli;
struct lov_stripe_md *lsm;
__u32 stripe;
__u64 kms;
+ /* This lock wasn't granted, don't try to evict pages */
+ if (lock->l_req_mode != lock->l_granted_mode)
+ RETURN(0);
+
+ inode = ll_inode_from_lock(lock);
if (inode == NULL)
RETURN(0);
lli = ll_i2info(inode);
LBUG();
}
- LDLM_DEBUG(lock, "i_size: %Lu -> stripe number %d -> size %Lu",
+ LDLM_DEBUG(lock, "i_size: %llu -> stripe number %u -> size "LPU64,
inode->i_size, data.stripe_number, data.size);
rc = lustre_pack_reply(req, 1, &size, NULL);
LCK_PR, &flags, ll_extent_lock_callback,
ldlm_completion_ast, ll_glimpse_callback, inode,
sizeof(*lvb), lustre_swab_ost_lvb, &lockh);
- if (rc > 0)
+ if (rc > 0) {
+ CERROR("obd_enqueue returned rc %d, returning -EIO\n", rc);
RETURN(-EIO);
+ }
lvb->lvb_size = lov_merge_size(lli->lli_smd, 0);
//inode->i_mtime = lov_merge_mtime(lli->lli_smd, inode->i_mtime);
inode->i_size = kms;
}
- CDEBUG(D_INFO, "Reading inode %lu, "LPSZ" bytes, offset %Ld, i_size "
- LPU64"\n", inode->i_ino, count, *ppos, inode->i_size);
+ CDEBUG(D_INFO, "Read ino %lu, "LPSZ" bytes, offset %lld, i_size %llu\n",
+ inode->i_ino, count, *ppos, inode->i_size);
/* turn off the kernel's read-ahead */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
CDEBUG(D_INFO, "trying to match res "LPU64"\n", res_id.name[0]);
+ /* FIXME use LDLM_FL_TEST_LOCK instead */
flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING;
if (ldlm_lock_match(obddev->obd_namespace, flags, &res_id, LDLM_PLAIN,
NULL, LCK_PR, &lockh)) {