ceph: perform lazy reads when file mode and caps permit
If the file mode is marked as "lazy," perform cached/buffered reads when the caps permit it. Adjust the rdcache_gen and invalidation logic accordingly so that we manage our cache based on the FILE_CACHE -or- FILE_LAZYIO cap bits. Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
@@ -552,7 +552,7 @@ static void writepages_finish(struct ceph_osd_request *req,
|
|||||||
* page truncation thread, possibly losing some data that
|
* page truncation thread, possibly losing some data that
|
||||||
* raced its way in
|
* raced its way in
|
||||||
*/
|
*/
|
||||||
if ((issued & CEPH_CAP_FILE_CACHE) == 0)
|
if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0)
|
||||||
generic_error_remove_page(inode->i_mapping, page);
|
generic_error_remove_page(inode->i_mapping, page);
|
||||||
|
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
|
@@ -482,8 +482,8 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
|
|||||||
* Each time we receive FILE_CACHE anew, we increment
|
* Each time we receive FILE_CACHE anew, we increment
|
||||||
* i_rdcache_gen.
|
* i_rdcache_gen.
|
||||||
*/
|
*/
|
||||||
if ((issued & CEPH_CAP_FILE_CACHE) &&
|
if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
|
||||||
(had & CEPH_CAP_FILE_CACHE) == 0)
|
(had & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0)
|
||||||
ci->i_rdcache_gen++;
|
ci->i_rdcache_gen++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1509,11 +1509,13 @@ retry_locked:
|
|||||||
ci->i_wrbuffer_ref == 0 && /* no dirty pages... */
|
ci->i_wrbuffer_ref == 0 && /* no dirty pages... */
|
||||||
ci->i_rdcache_gen && /* may have cached pages */
|
ci->i_rdcache_gen && /* may have cached pages */
|
||||||
(file_wanted == 0 || /* no open files */
|
(file_wanted == 0 || /* no open files */
|
||||||
(revoking & CEPH_CAP_FILE_CACHE)) && /* or revoking cache */
|
(revoking & (CEPH_CAP_FILE_CACHE|
|
||||||
|
CEPH_CAP_FILE_LAZYIO))) && /* or revoking cache */
|
||||||
!tried_invalidate) {
|
!tried_invalidate) {
|
||||||
dout("check_caps trying to invalidate on %p\n", inode);
|
dout("check_caps trying to invalidate on %p\n", inode);
|
||||||
if (try_nonblocking_invalidate(inode) < 0) {
|
if (try_nonblocking_invalidate(inode) < 0) {
|
||||||
if (revoking & CEPH_CAP_FILE_CACHE) {
|
if (revoking & (CEPH_CAP_FILE_CACHE|
|
||||||
|
CEPH_CAP_FILE_LAZYIO)) {
|
||||||
dout("check_caps queuing invalidate\n");
|
dout("check_caps queuing invalidate\n");
|
||||||
queue_invalidate = 1;
|
queue_invalidate = 1;
|
||||||
ci->i_rdcache_revoking = ci->i_rdcache_gen;
|
ci->i_rdcache_revoking = ci->i_rdcache_gen;
|
||||||
@@ -2276,7 +2278,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
|
|||||||
* try to invalidate (once). (If there are dirty buffers, we
|
* try to invalidate (once). (If there are dirty buffers, we
|
||||||
* will invalidate _after_ writeback.)
|
* will invalidate _after_ writeback.)
|
||||||
*/
|
*/
|
||||||
if (((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) &&
|
if (((cap->issued & ~newcaps) & (CEPH_CAP_FILE_CACHE|
|
||||||
|
CEPH_CAP_FILE_LAZYIO)) &&
|
||||||
!ci->i_wrbuffer_ref) {
|
!ci->i_wrbuffer_ref) {
|
||||||
if (try_nonblocking_invalidate(inode) == 0) {
|
if (try_nonblocking_invalidate(inode) == 0) {
|
||||||
revoked_rdcache = 1;
|
revoked_rdcache = 1;
|
||||||
@@ -2374,7 +2377,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
|
|||||||
writeback = 1; /* will delay ack */
|
writeback = 1; /* will delay ack */
|
||||||
else if (dirty & ~newcaps)
|
else if (dirty & ~newcaps)
|
||||||
check_caps = 1; /* initiate writeback in check_caps */
|
check_caps = 1; /* initiate writeback in check_caps */
|
||||||
else if (((used & ~newcaps) & CEPH_CAP_FILE_CACHE) == 0 ||
|
else if (((used & ~newcaps) & (CEPH_CAP_FILE_CACHE|
|
||||||
|
CEPH_CAP_FILE_LAZYIO)) == 0 ||
|
||||||
revoked_rdcache)
|
revoked_rdcache)
|
||||||
check_caps = 2; /* send revoke ack in check_caps */
|
check_caps = 2; /* send revoke ack in check_caps */
|
||||||
cap->issued = newcaps;
|
cap->issued = newcaps;
|
||||||
|
@@ -740,28 +740,32 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
|
|||||||
unsigned long nr_segs, loff_t pos)
|
unsigned long nr_segs, loff_t pos)
|
||||||
{
|
{
|
||||||
struct file *filp = iocb->ki_filp;
|
struct file *filp = iocb->ki_filp;
|
||||||
|
struct ceph_file_info *fi = filp->private_data;
|
||||||
loff_t *ppos = &iocb->ki_pos;
|
loff_t *ppos = &iocb->ki_pos;
|
||||||
size_t len = iov->iov_len;
|
size_t len = iov->iov_len;
|
||||||
struct inode *inode = filp->f_dentry->d_inode;
|
struct inode *inode = filp->f_dentry->d_inode;
|
||||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||||
void *base = iov->iov_base;
|
void *base = iov->iov_base;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
int got = 0;
|
int want, got = 0;
|
||||||
int checkeof = 0, read = 0;
|
int checkeof = 0, read = 0;
|
||||||
|
|
||||||
dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n",
|
dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n",
|
||||||
inode, ceph_vinop(inode), pos, (unsigned)len, inode);
|
inode, ceph_vinop(inode), pos, (unsigned)len, inode);
|
||||||
again:
|
again:
|
||||||
__ceph_do_pending_vmtruncate(inode);
|
__ceph_do_pending_vmtruncate(inode);
|
||||||
ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, CEPH_CAP_FILE_CACHE,
|
if (fi->fmode & CEPH_FILE_MODE_LAZY)
|
||||||
&got, -1);
|
want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
|
||||||
|
else
|
||||||
|
want = CEPH_CAP_FILE_CACHE;
|
||||||
|
ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
|
dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
|
||||||
inode, ceph_vinop(inode), pos, (unsigned)len,
|
inode, ceph_vinop(inode), pos, (unsigned)len,
|
||||||
ceph_cap_string(got));
|
ceph_cap_string(got));
|
||||||
|
|
||||||
if ((got & CEPH_CAP_FILE_CACHE) == 0 ||
|
if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
|
||||||
(iocb->ki_filp->f_flags & O_DIRECT) ||
|
(iocb->ki_filp->f_flags & O_DIRECT) ||
|
||||||
(inode->i_sb->s_flags & MS_SYNCHRONOUS))
|
(inode->i_sb->s_flags & MS_SYNCHRONOUS))
|
||||||
/* hmm, this isn't really async... */
|
/* hmm, this isn't really async... */
|
||||||
|
@@ -442,8 +442,9 @@ int ceph_fill_file_size(struct inode *inode, int issued,
|
|||||||
* the file is either opened or mmaped
|
* the file is either opened or mmaped
|
||||||
*/
|
*/
|
||||||
if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD|
|
if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD|
|
||||||
CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
|
CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
|
||||||
CEPH_CAP_FILE_EXCL)) ||
|
CEPH_CAP_FILE_EXCL|
|
||||||
|
CEPH_CAP_FILE_LAZYIO)) ||
|
||||||
mapping_mapped(inode->i_mapping) ||
|
mapping_mapped(inode->i_mapping) ||
|
||||||
__ceph_caps_file_wanted(ci)) {
|
__ceph_caps_file_wanted(ci)) {
|
||||||
ci->i_truncate_pending++;
|
ci->i_truncate_pending++;
|
||||||
|
Reference in New Issue
Block a user