Commit 719a2514 authored by Yan, Zheng's avatar Yan, Zheng Committed by Ilya Dryomov
Browse files

ceph: consider inode's last read/write when calculating wanted caps



Add i_last_rd and i_last_wr to ceph_inode_info. These fields are
used to track the last time the client acquired read/write caps for
the inode.

If there is no read/write on an inode for 'caps_wanted_delay_max'
seconds, __ceph_caps_file_wanted() does not request caps for read/write
even there are open files.

Call __ceph_touch_fmode() for dir operations. __ceph_caps_file_wanted()
calculates dir's wanted caps according to last dir read/modification. If
there is recent dir read, dir inode wants CEPH_CAP_ANY_SHARED caps. If
there is recent dir modification, also wants CEPH_CAP_FILE_EXCL.

Readdir is a special case. Dir inode wants CEPH_CAP_FILE_EXCL after
readdir, as with that, modifications do not need to release
CEPH_CAP_FILE_SHARED or invalidate all dentry leases issued by readdir.

Signed-off-by: default avatar"Yan, Zheng" <zyan@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent c0e385b1
Loading
Loading
Loading
Loading
+129 −54
Original line number Diff line number Diff line
@@ -978,19 +978,67 @@ int __ceph_caps_used(struct ceph_inode_info *ci)
	return used;
}

#define FMODE_WAIT_BIAS 1000

/*
 * wanted, by virtue of open file modes
 */
int __ceph_caps_file_wanted(struct ceph_inode_info *ci)
{
	int i, bits = 0;
	for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
		if (ci->i_nr_by_mode[i])
			bits |= 1 << i;
	const int PIN_SHIFT = ffs(CEPH_FILE_MODE_PIN);
	const int RD_SHIFT = ffs(CEPH_FILE_MODE_RD);
	const int WR_SHIFT = ffs(CEPH_FILE_MODE_WR);
	const int LAZY_SHIFT = ffs(CEPH_FILE_MODE_LAZY);
	struct ceph_mount_options *opt =
		ceph_inode_to_client(&ci->vfs_inode)->mount_options;
	unsigned long used_cutoff = jiffies - opt->caps_wanted_delay_max * HZ;
	unsigned long idle_cutoff = jiffies - opt->caps_wanted_delay_min * HZ;

	if (S_ISDIR(ci->vfs_inode.i_mode)) {
		int want = 0;

		/* use used_cutoff here, to keep dir's wanted caps longer */
		if (ci->i_nr_by_mode[RD_SHIFT] > 0 ||
		    time_after(ci->i_last_rd, used_cutoff))
			want |= CEPH_CAP_ANY_SHARED;

		if (ci->i_nr_by_mode[WR_SHIFT] > 0 ||
		    time_after(ci->i_last_wr, used_cutoff)) {
			want |= CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_EXCL;
			if (opt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS)
				want |= CEPH_CAP_ANY_DIR_OPS;
		}

		if (want || ci->i_nr_by_mode[PIN_SHIFT] > 0)
			want |= CEPH_CAP_PIN;

		return want;
	} else {
		int bits = 0;

		if (ci->i_nr_by_mode[RD_SHIFT] > 0) {
			if (ci->i_nr_by_mode[RD_SHIFT] >= FMODE_WAIT_BIAS ||
			    time_after(ci->i_last_rd, used_cutoff))
				bits |= 1 << RD_SHIFT;
		} else if (time_after(ci->i_last_rd, idle_cutoff)) {
			bits |= 1 << RD_SHIFT;
		}

		if (ci->i_nr_by_mode[WR_SHIFT] > 0) {
			if (ci->i_nr_by_mode[WR_SHIFT] >= FMODE_WAIT_BIAS ||
			    time_after(ci->i_last_wr, used_cutoff))
				bits |= 1 << WR_SHIFT;
		} else if (time_after(ci->i_last_wr, idle_cutoff)) {
			bits |= 1 << WR_SHIFT;
		}

		/* check lazyio only when read/write is wanted */
		if ((bits & (CEPH_FILE_MODE_RDWR << 1)) &&
		    ci->i_nr_by_mode[LAZY_SHIFT] > 0)
			bits |= 1 << LAZY_SHIFT;

		return bits ? ceph_caps_for_mode(bits >> 1) : 0;
	}
	if (bits == 0)
		return 0;
	return ceph_caps_for_mode(bits >> 1);
}

/*
@@ -1032,14 +1080,6 @@ int __ceph_caps_mds_wanted(struct ceph_inode_info *ci, bool check)
	return mds_wanted;
}

/*
 * called under i_ceph_lock
 */
static int __ceph_is_single_caps(struct ceph_inode_info *ci)
{
	return rb_first(&ci->i_caps) == rb_last(&ci->i_caps);
}

int ceph_is_any_caps(struct inode *inode)
{
	struct ceph_inode_info *ci = ceph_inode(inode);
@@ -1877,10 +1917,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags,
	if (ci->i_ceph_flags & CEPH_I_FLUSH)
		flags |= CHECK_CAPS_FLUSH;

	if (!(flags & CHECK_CAPS_AUTHONLY) ||
	    (ci->i_auth_cap && __ceph_is_single_caps(ci)))
		__cap_delay_cancel(mdsc, ci);

	goto retry_locked;
retry:
	spin_lock(&ci->i_ceph_lock);
@@ -1907,9 +1943,7 @@ retry_locked:
			if (IS_RDONLY(inode)) {
				want = CEPH_CAP_ANY_SHARED;
			} else {
				want = CEPH_CAP_ANY_SHARED |
				       CEPH_CAP_FILE_EXCL |
				       CEPH_CAP_ANY_DIR_OPS;
				want |= CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_EXCL;
			}
			retain |= want;
		} else {
@@ -2105,9 +2139,17 @@ ack:
		goto retry; /* retake i_ceph_lock and restart our cap scan. */
	}

	if (list_empty(&ci->i_cap_delay_list)) {
	    if (delayed) {
		    /* Reschedule delayed caps release if we delayed anything */
	if (delayed)
		    __cap_delay_requeue(mdsc, ci, false);
	    } else if (__ceph_is_any_real_caps(ci) &&
			(file_wanted & ~CEPH_CAP_PIN) &&
			!(used & (CEPH_CAP_FILE_RD | CEPH_CAP_ANY_FILE_WR))) {
		    /* periodically re-calculate caps wanted by open files */
		    __cap_delay_requeue(mdsc, ci, true);
	    }
	}

	spin_unlock(&ci->i_ceph_lock);

@@ -2573,8 +2615,9 @@ void ceph_take_cap_refs(struct ceph_inode_info *ci, int got,
 * FIXME: how does a 0 return differ from -EAGAIN?
 */
enum {
	NON_BLOCKING	= 1,
	CHECK_FILELOCK	= 2,
	/* first 8 bits are reserved for CEPH_FILE_MODE_FOO */
	NON_BLOCKING	= (1 << 8),
	CHECK_FILELOCK	= (1 << 9),
};

static int try_get_cap_refs(struct inode *inode, int need, int want,
@@ -2584,7 +2627,6 @@ static int try_get_cap_refs(struct inode *inode, int need, int want,
	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
	int ret = 0;
	int have, implemented;
	int file_wanted;
	bool snap_rwsem_locked = false;

	dout("get_cap_refs %p need %s want %s\n", inode,
@@ -2600,15 +2642,6 @@ again:
		goto out_unlock;
	}

	/* make sure file is actually open */
	file_wanted = __ceph_caps_file_wanted(ci);
	if ((file_wanted & need) != need) {
		dout("try_get_cap_refs need %s file_wanted %s, EBADF\n",
		     ceph_cap_string(need), ceph_cap_string(file_wanted));
		ret = -EBADF;
		goto out_unlock;
	}

	/* finish pending truncate */
	while (ci->i_truncate_pending) {
		spin_unlock(&ci->i_ceph_lock);
@@ -2719,6 +2752,9 @@ again:
		     ceph_cap_string(have), ceph_cap_string(need));
	}
out_unlock:

	__ceph_touch_fmode(ci, mdsc, flags);

	spin_unlock(&ci->i_ceph_lock);
	if (snap_rwsem_locked)
		up_read(&mdsc->snap_rwsem);
@@ -2756,10 +2792,20 @@ static void check_max_size(struct inode *inode, loff_t endoff)
		ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
}

static inline int get_used_fmode(int caps)
{
	int fmode = 0;
	if (caps & CEPH_CAP_FILE_RD)
		fmode |= CEPH_FILE_MODE_RD;
	if (caps & CEPH_CAP_FILE_WR)
		fmode |= CEPH_FILE_MODE_WR;
	return fmode;
}

int ceph_try_get_caps(struct inode *inode, int need, int want,
		      bool nonblock, int *got)
{
	int ret;
	int ret, flags;

	BUG_ON(need & ~CEPH_CAP_FILE_RD);
	BUG_ON(want & ~(CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO |
@@ -2771,8 +2817,11 @@ int ceph_try_get_caps(struct inode *inode, int need, int want,
			return ret;
	}

	ret = try_get_cap_refs(inode, need, want, 0,
			       (nonblock ? NON_BLOCKING : 0), got);
	flags = get_used_fmode(need | want);
	if (nonblock)
		flags |= NON_BLOCKING;

	ret = try_get_cap_refs(inode, need, want, 0, flags, got);
	return ret == -EAGAIN ? 0 : ret;
}

@@ -2798,11 +2847,15 @@ int ceph_get_caps(struct file *filp, int need, int want,
	    fi->filp_gen != READ_ONCE(fsc->filp_gen))
		return -EBADF;

	flags = get_used_fmode(need | want);

	while (true) {
		if (endoff > 0)
			check_max_size(inode, endoff);

		flags = atomic_read(&fi->num_locks) ? CHECK_FILELOCK : 0;
		flags &= CEPH_FILE_MODE_MASK;
		if (atomic_read(&fi->num_locks))
			flags |= CHECK_FILELOCK;
		_got = 0;
		ret = try_get_cap_refs(inode, need, want, endoff,
				       flags, &_got);
@@ -2822,6 +2875,8 @@ int ceph_get_caps(struct file *filp, int need, int want,
			list_add(&cw.list, &mdsc->cap_wait_list);
			spin_unlock(&mdsc->caps_list_lock);

			/* make sure used fmode not timeout */
			ceph_get_fmode(ci, flags, FMODE_WAIT_BIAS);
			add_wait_queue(&ci->i_cap_wq, &wait);

			flags |= NON_BLOCKING;
@@ -2835,6 +2890,7 @@ int ceph_get_caps(struct file *filp, int need, int want,
			}

			remove_wait_queue(&ci->i_cap_wq, &wait);
			ceph_put_fmode(ci, flags, FMODE_WAIT_BIAS);

			spin_lock(&mdsc->caps_list_lock);
			list_del(&cw.list);
@@ -2854,7 +2910,7 @@ int ceph_get_caps(struct file *filp, int need, int want,
		if (ret < 0) {
			if (ret == -ESTALE) {
				/* session was killed, try renew caps */
				ret = ceph_renew_caps(inode);
				ret = ceph_renew_caps(inode, flags);
				if (ret == 0)
					continue;
			}
@@ -4153,6 +4209,33 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
	dout("flush_dirty_caps done\n");
}

void __ceph_touch_fmode(struct ceph_inode_info *ci,
			struct ceph_mds_client *mdsc, int fmode)
{
	unsigned long now = jiffies;
	if (fmode & CEPH_FILE_MODE_RD)
		ci->i_last_rd = now;
	if (fmode & CEPH_FILE_MODE_WR)
		ci->i_last_wr = now;
	/* queue periodic check */
	if (fmode &&
	    __ceph_is_any_real_caps(ci) &&
	    list_empty(&ci->i_cap_delay_list))
		__cap_delay_requeue(mdsc, ci, true);
}

void ceph_get_fmode(struct ceph_inode_info *ci, int fmode, int count)
{
	int i;
	int bits = (fmode << 1) | 1;
	spin_lock(&ci->i_ceph_lock);
	for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
		if (bits & (1 << i))
			ci->i_nr_by_mode[i] += count;
	}
	spin_unlock(&ci->i_ceph_lock);
}

void __ceph_get_fmode(struct ceph_inode_info *ci, int fmode)
{
	int i;
@@ -4168,26 +4251,18 @@ void __ceph_get_fmode(struct ceph_inode_info *ci, int fmode)
 * we may need to release capabilities to the MDS (or schedule
 * their delayed release).
 */
void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
void ceph_put_fmode(struct ceph_inode_info *ci, int fmode, int count)
{
	int i, last = 0;
	int i;
	int bits = (fmode << 1) | 1;
	spin_lock(&ci->i_ceph_lock);
	for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
		if (bits & (1 << i)) {
			BUG_ON(ci->i_nr_by_mode[i] == 0);
			if (--ci->i_nr_by_mode[i] == 0)
				last++;
			BUG_ON(ci->i_nr_by_mode[i] < count);
			ci->i_nr_by_mode[i] -= count;
		}
	}
	dout("put_fmode %p fmode %d {%d,%d,%d,%d}\n",
	     &ci->vfs_inode, fmode,
	     ci->i_nr_by_mode[0], ci->i_nr_by_mode[1],
	     ci->i_nr_by_mode[2], ci->i_nr_by_mode[3]);
	spin_unlock(&ci->i_ceph_lock);

	if (last && ci->i_vino.snap == CEPH_NOSNAP)
		ceph_check_caps(ci, 0, NULL);
}

/*
+15 −6
Original line number Diff line number Diff line
@@ -335,8 +335,11 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
		ctx->pos = 2;
	}

	/* can we use the dcache? */
	spin_lock(&ci->i_ceph_lock);
	/* request Fx cap. if have Fx, we don't need to release Fs cap
	 * for later create/unlink. */
	__ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_WR);
	/* can we use the dcache? */
	if (ceph_test_mount_opt(fsc, DCACHE) &&
	    !ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
	    ceph_snap(inode) != CEPH_SNAPDIR &&
@@ -760,6 +763,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
		    ceph_test_mount_opt(fsc, DCACHE) &&
		    __ceph_dir_is_complete(ci) &&
		    (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
			__ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
			spin_unlock(&ci->i_ceph_lock);
			dout(" dir %p complete, -ENOENT\n", dir);
			d_add(dentry, NULL);
@@ -1621,7 +1625,8 @@ static int __dir_lease_try_check(const struct dentry *dentry)
/*
 * Check if directory-wide content lease/cap is valid.
 */
static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry,
			      struct ceph_mds_client *mdsc)
{
	struct ceph_inode_info *ci = ceph_inode(dir);
	int valid;
@@ -1629,7 +1634,10 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)

	spin_lock(&ci->i_ceph_lock);
	valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
	if (valid) {
		__ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
		shared_gen = atomic_read(&ci->i_shared_gen);
	}
	spin_unlock(&ci->i_ceph_lock);
	if (valid) {
		struct ceph_dentry_info *di;
@@ -1655,6 +1663,7 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
	int valid = 0;
	struct dentry *parent;
	struct inode *dir, *inode;
	struct ceph_mds_client *mdsc;

	if (flags & LOOKUP_RCU) {
		parent = READ_ONCE(dentry->d_parent);
@@ -1671,6 +1680,8 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
	dout("d_revalidate %p '%pd' inode %p offset 0x%llx\n", dentry,
	     dentry, inode, ceph_dentry(dentry)->offset);

	mdsc = ceph_sb_to_client(dir->i_sb)->mdsc;

	/* always trust cached snapped dentries, snapdir dentry */
	if (ceph_snap(dir) != CEPH_NOSNAP) {
		dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
@@ -1682,7 +1693,7 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
		valid = dentry_lease_is_valid(dentry, flags);
		if (valid == -ECHILD)
			return valid;
		if (valid || dir_lease_is_valid(dir, dentry)) {
		if (valid || dir_lease_is_valid(dir, dentry, mdsc)) {
			if (inode)
				valid = ceph_is_any_caps(inode);
			else
@@ -1691,8 +1702,6 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
	}

	if (!valid) {
		struct ceph_mds_client *mdsc =
			ceph_sb_to_client(dir->i_sb)->mdsc;
		struct ceph_mds_request *req;
		int op, err;
		u32 mask;
+12 −9
Original line number Diff line number Diff line
@@ -213,7 +213,7 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
		struct ceph_dir_file_info *dfi =
			kmem_cache_zalloc(ceph_dir_file_cachep, GFP_KERNEL);
		if (!dfi) {
			ceph_put_fmode(ci, fmode); /* clean up */
			ceph_put_fmode(ci, fmode, 1); /* clean up */
			return -ENOMEM;
		}

@@ -224,7 +224,7 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
	} else {
		fi = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
		if (!fi) {
			ceph_put_fmode(ci, fmode); /* clean up */
			ceph_put_fmode(ci, fmode, 1); /* clean up */
			return -ENOMEM;
		}

@@ -263,7 +263,7 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
	case S_IFLNK:
		dout("init_file %p %p 0%o (symlink)\n", inode, file,
		     inode->i_mode);
		ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
		ceph_put_fmode(ceph_inode(inode), fmode, 1); /* clean up */
		break;

	default:
@@ -273,7 +273,7 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
		 * we need to drop the open ref now, since we don't
		 * have .release set to ceph_release.
		 */
		ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
		ceph_put_fmode(ceph_inode(inode), fmode, 1); /* clean up */
		BUG_ON(inode->i_fop->release == ceph_release);

		/* call the proper open fop */
@@ -285,14 +285,15 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
/*
 * try renew caps after session gets killed.
 */
int ceph_renew_caps(struct inode *inode)
int ceph_renew_caps(struct inode *inode, int fmode)
{
	struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
	struct ceph_inode_info *ci = ceph_inode(inode);
	struct ceph_mds_request *req;
	int err, flags, wanted;

	spin_lock(&ci->i_ceph_lock);
	__ceph_touch_fmode(ci, mdsc, fmode);
	wanted = __ceph_caps_file_wanted(ci);
	if (__ceph_is_any_real_caps(ci) &&
	    (!(wanted & CEPH_CAP_ANY_WR) || ci->i_auth_cap)) {
@@ -405,6 +406,7 @@ int ceph_open(struct inode *inode, struct file *file)
	} else if (ceph_snap(inode) != CEPH_NOSNAP &&
		   (ci->i_snap_caps & wanted) == wanted) {
		__ceph_get_fmode(ci, fmode);
		__ceph_touch_fmode(ci, mdsc, fmode);
		spin_unlock(&ci->i_ceph_lock);
		return ceph_init_file(inode, file, fmode);
	}
@@ -781,7 +783,7 @@ retry:
	}
out_req:
	if (!req->r_err && req->r_target_inode)
		ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode);
		ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode, 1);
	ceph_mdsc_put_request(req);
out_ctx:
	ceph_release_acl_sec_ctx(&as_ctx);
@@ -798,7 +800,7 @@ int ceph_release(struct inode *inode, struct file *file)
		dout("release inode %p dir file %p\n", inode, file);
		WARN_ON(!list_empty(&dfi->file_info.rw_contexts));

		ceph_put_fmode(ci, dfi->file_info.fmode);
		ceph_put_fmode(ci, dfi->file_info.fmode, 1);

		if (dfi->last_readdir)
			ceph_mdsc_put_request(dfi->last_readdir);
@@ -810,7 +812,8 @@ int ceph_release(struct inode *inode, struct file *file)
		dout("release inode %p regular file %p\n", inode, file);
		WARN_ON(!list_empty(&fi->rw_contexts));

		ceph_put_fmode(ci, fi->fmode);
		ceph_put_fmode(ci, fi->fmode, 1);

		kmem_cache_free(ceph_file_cachep, fi);
	}

+9 −1
Original line number Diff line number Diff line
@@ -479,6 +479,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
	ci->i_head_snapc = NULL;
	ci->i_snap_caps = 0;

	ci->i_last_rd = ci->i_last_wr = jiffies - 3600 * HZ;
	for (i = 0; i < CEPH_FILE_MODE_BITS; i++)
		ci->i_nr_by_mode[i] = 0;

@@ -639,7 +640,7 @@ int ceph_fill_file_size(struct inode *inode, int issued,
			if ((issued & (CEPH_CAP_FILE_CACHE|
				       CEPH_CAP_FILE_BUFFER)) ||
			    mapping_mapped(inode->i_mapping) ||
			    __ceph_caps_file_wanted(ci)) {
			    __ceph_is_file_opened(ci)) {
				ci->i_truncate_pending++;
				queue_trunc = 1;
			}
@@ -1013,6 +1014,13 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
			fill_inline = true;
	}

	if (cap_fmode >= 0) {
		if (!info_caps)
			pr_warn("mds issued no caps on %llx.%llx\n",
				ceph_vinop(inode));
		__ceph_touch_fmode(ci, mdsc, cap_fmode);
	}

	spin_unlock(&ci->i_ceph_lock);

	if (fill_inline)
+2 −0
Original line number Diff line number Diff line
@@ -243,11 +243,13 @@ static long ceph_ioctl_lazyio(struct file *file)
	struct ceph_file_info *fi = file->private_data;
	struct inode *inode = file_inode(file);
	struct ceph_inode_info *ci = ceph_inode(inode);
	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;

	if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
		spin_lock(&ci->i_ceph_lock);
		fi->fmode |= CEPH_FILE_MODE_LAZY;
		ci->i_nr_by_mode[ffs(CEPH_FILE_MODE_LAZY)]++;
		__ceph_touch_fmode(ci, mdsc, fi->fmode);
		spin_unlock(&ci->i_ceph_lock);
		dout("ioctl_layzio: file %p marked lazy\n", file);

Loading