Commit 20bf195e authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ceph-for-5.12-rc1' of git://github.com/ceph/ceph-client

Pull ceph updates from Ilya Dryomov:
 "With netfs helper library and fscache rework delayed, just a few cap
  handling improvements to avoid grabbing mmap_lock in some code paths
  and deal with capsnaps better and a mount option cleanup"

* tag 'ceph-for-5.12-rc1' of git://github.com/ceph/ceph-client:
  ceph: defer flushing the capsnap if the Fb is used
  libceph: remove osdtimeout option entirely
  libceph: deprecate [no]cephx_require_signatures options
  ceph: allow queueing cap/snap handling after putting cap references
  ceph: clean up inode work queueing
  ceph: fix flush_snap logic after putting caps
parents 9fe19046 558b4510
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1662,7 +1662,7 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)

	dout("page_mkwrite %p %llu~%zd dropping cap refs on %s ret %x\n",
	     inode, off, len, ceph_cap_string(got), ret);
	ceph_put_cap_refs(ci, got);
	ceph_put_cap_refs_async(ci, got);
out_free:
	ceph_restore_sigs(&oldset);
	sb_end_pagefault(inode->i_sb);
+50 −20
Original line number Diff line number Diff line
@@ -3027,6 +3027,12 @@ static int ceph_try_drop_cap_snap(struct ceph_inode_info *ci,
	return 0;
}

enum put_cap_refs_mode {
	PUT_CAP_REFS_SYNC = 0,
	PUT_CAP_REFS_NO_CHECK,
	PUT_CAP_REFS_ASYNC,
};

/*
 * Release cap refs.
 *
@@ -3037,10 +3043,11 @@ static int ceph_try_drop_cap_snap(struct ceph_inode_info *ci,
 * cap_snap, and wake up any waiters.
 */
static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had,
				bool skip_checking_caps)
				enum put_cap_refs_mode mode)
{
	struct inode *inode = &ci->vfs_inode;
	int last = 0, put = 0, flushsnaps = 0, wake = 0;
	bool check_flushsnaps = false;

	spin_lock(&ci->i_ceph_lock);
	if (had & CEPH_CAP_PIN)
@@ -3057,26 +3064,17 @@ static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had,
	if (had & CEPH_CAP_FILE_BUFFER) {
		if (--ci->i_wb_ref == 0) {
			last++;
			/* put the ref held by ceph_take_cap_refs() */
			put++;
			check_flushsnaps = true;
		}
		dout("put_cap_refs %p wb %d -> %d (?)\n",
		     inode, ci->i_wb_ref+1, ci->i_wb_ref);
	}
	if (had & CEPH_CAP_FILE_WR)
	if (had & CEPH_CAP_FILE_WR) {
		if (--ci->i_wr_ref == 0) {
			last++;
			if (__ceph_have_pending_cap_snap(ci)) {
				struct ceph_cap_snap *capsnap =
					list_last_entry(&ci->i_cap_snaps,
							struct ceph_cap_snap,
							ci_item);
				capsnap->writing = 0;
				if (ceph_try_drop_cap_snap(ci, capsnap))
					put++;
				else if (__ceph_finish_cap_snap(ci, capsnap))
					flushsnaps = 1;
				wake = 1;
			}
			check_flushsnaps = true;
			if (ci->i_wrbuffer_ref_head == 0 &&
			    ci->i_dirty_caps == 0 &&
			    ci->i_flushing_caps == 0) {
@@ -3088,15 +3086,42 @@ static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had,
			if (!__ceph_is_any_real_caps(ci) && ci->i_snap_realm)
				drop_inode_snap_realm(ci);
		}
	}
	if (check_flushsnaps && __ceph_have_pending_cap_snap(ci)) {
		struct ceph_cap_snap *capsnap =
			list_last_entry(&ci->i_cap_snaps,
					struct ceph_cap_snap,
					ci_item);

		capsnap->writing = 0;
		if (ceph_try_drop_cap_snap(ci, capsnap))
			/* put the ref held by ceph_queue_cap_snap() */
			put++;
		else if (__ceph_finish_cap_snap(ci, capsnap))
			flushsnaps = 1;
		wake = 1;
	}
	spin_unlock(&ci->i_ceph_lock);

	dout("put_cap_refs %p had %s%s%s\n", inode, ceph_cap_string(had),
	     last ? " last" : "", put ? " put" : "");

	if (last && !skip_checking_caps)
	switch (mode) {
	case PUT_CAP_REFS_SYNC:
		if (last)
			ceph_check_caps(ci, 0, NULL);
		else if (flushsnaps)
			ceph_flush_snaps(ci, NULL);
		break;
	case PUT_CAP_REFS_ASYNC:
		if (last)
			ceph_queue_check_caps(inode);
		else if (flushsnaps)
			ceph_queue_flush_snaps(inode);
		break;
	default:
		break;
	}
	if (wake)
		wake_up_all(&ci->i_cap_wq);
	while (put-- > 0)
@@ -3105,12 +3130,17 @@ static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had,

void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
{
	__ceph_put_cap_refs(ci, had, false);
	__ceph_put_cap_refs(ci, had, PUT_CAP_REFS_SYNC);
}

void ceph_put_cap_refs_async(struct ceph_inode_info *ci, int had)
{
	__ceph_put_cap_refs(ci, had, PUT_CAP_REFS_ASYNC);
}

void ceph_put_cap_refs_no_check_caps(struct ceph_inode_info *ci, int had)
{
	__ceph_put_cap_refs(ci, had, true);
	__ceph_put_cap_refs(ci, had, PUT_CAP_REFS_NO_CHECK);
}

/*
+12 −49
Original line number Diff line number Diff line
@@ -1816,60 +1816,17 @@ void ceph_async_iput(struct inode *inode)
	}
}

/*
 * Write back inode data in a worker thread.  (This can't be done
 * in the message handler context.)
 */
void ceph_queue_writeback(struct inode *inode)
{
	struct ceph_inode_info *ci = ceph_inode(inode);
	set_bit(CEPH_I_WORK_WRITEBACK, &ci->i_work_mask);

	ihold(inode);
	if (queue_work(ceph_inode_to_client(inode)->inode_wq,
		       &ci->i_work)) {
		dout("ceph_queue_writeback %p\n", inode);
	} else {
		dout("ceph_queue_writeback %p already queued, mask=%lx\n",
		     inode, ci->i_work_mask);
		iput(inode);
	}
}

/*
 * queue an async invalidation
 */
void ceph_queue_invalidate(struct inode *inode)
{
	struct ceph_inode_info *ci = ceph_inode(inode);
	set_bit(CEPH_I_WORK_INVALIDATE_PAGES, &ci->i_work_mask);

	ihold(inode);
	if (queue_work(ceph_inode_to_client(inode)->inode_wq,
		       &ceph_inode(inode)->i_work)) {
		dout("ceph_queue_invalidate %p\n", inode);
	} else {
		dout("ceph_queue_invalidate %p already queued, mask=%lx\n",
		     inode, ci->i_work_mask);
		iput(inode);
	}
}

/*
 * Queue an async vmtruncate.  If we fail to queue work, we will handle
 * the truncation the next time we call __ceph_do_pending_vmtruncate.
 */
void ceph_queue_vmtruncate(struct inode *inode)
void ceph_queue_inode_work(struct inode *inode, int work_bit)
{
	struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
	struct ceph_inode_info *ci = ceph_inode(inode);
	set_bit(CEPH_I_WORK_VMTRUNCATE, &ci->i_work_mask);
	set_bit(work_bit, &ci->i_work_mask);

	ihold(inode);
	if (queue_work(ceph_inode_to_client(inode)->inode_wq,
		       &ci->i_work)) {
		dout("ceph_queue_vmtruncate %p\n", inode);
	if (queue_work(fsc->inode_wq, &ci->i_work)) {
		dout("queue_inode_work %p, mask=%lx\n", inode, ci->i_work_mask);
	} else {
		dout("ceph_queue_vmtruncate %p already queued, mask=%lx\n",
		dout("queue_inode_work %p already queued, mask=%lx\n",
		     inode, ci->i_work_mask);
		iput(inode);
	}
@@ -2008,6 +1965,12 @@ static void ceph_inode_work(struct work_struct *work)
	if (test_and_clear_bit(CEPH_I_WORK_VMTRUNCATE, &ci->i_work_mask))
		__ceph_do_pending_vmtruncate(inode);

	if (test_and_clear_bit(CEPH_I_WORK_CHECK_CAPS, &ci->i_work_mask))
		ceph_check_caps(ci, 0, NULL);

	if (test_and_clear_bit(CEPH_I_WORK_FLUSH_SNAPS, &ci->i_work_mask))
		ceph_flush_snaps(ci, NULL);

	iput(inode);
}

+10 −0
Original line number Diff line number Diff line
@@ -623,6 +623,16 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
		return 0;
	}

	/* Fb cap still in use, delay it */
	if (ci->i_wb_ref) {
		dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu "
		     "used WRBUFFER, delaying\n", inode, capsnap,
		     capsnap->context, capsnap->context->seq,
		     ceph_cap_string(capsnap->dirty), capsnap->size);
		capsnap->writing = 1;
		return 0;
	}

	ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
	dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu\n",
	     inode, capsnap, capsnap->context,
+34 −6
Original line number Diff line number Diff line
@@ -562,9 +562,11 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
/*
 * Masks of ceph inode work.
 */
#define CEPH_I_WORK_WRITEBACK		0 /* writeback */
#define CEPH_I_WORK_INVALIDATE_PAGES	1 /* invalidate pages */
#define CEPH_I_WORK_VMTRUNCATE		2 /* vmtruncate */
#define CEPH_I_WORK_WRITEBACK		0
#define CEPH_I_WORK_INVALIDATE_PAGES	1
#define CEPH_I_WORK_VMTRUNCATE		2
#define CEPH_I_WORK_CHECK_CAPS		3
#define CEPH_I_WORK_FLUSH_SNAPS		4

/*
 * We set the ERROR_WRITE bit when we start seeing write errors on an inode
@@ -962,11 +964,36 @@ extern int ceph_inode_holds_cap(struct inode *inode, int mask);

extern bool ceph_inode_set_size(struct inode *inode, loff_t size);
extern void __ceph_do_pending_vmtruncate(struct inode *inode);
extern void ceph_queue_vmtruncate(struct inode *inode);
extern void ceph_queue_invalidate(struct inode *inode);
extern void ceph_queue_writeback(struct inode *inode);

extern void ceph_async_iput(struct inode *inode);

void ceph_queue_inode_work(struct inode *inode, int work_bit);

static inline void ceph_queue_vmtruncate(struct inode *inode)
{
	ceph_queue_inode_work(inode, CEPH_I_WORK_VMTRUNCATE);
}

static inline void ceph_queue_invalidate(struct inode *inode)
{
	ceph_queue_inode_work(inode, CEPH_I_WORK_INVALIDATE_PAGES);
}

static inline void ceph_queue_writeback(struct inode *inode)
{
	ceph_queue_inode_work(inode, CEPH_I_WORK_WRITEBACK);
}

static inline void ceph_queue_check_caps(struct inode *inode)
{
	ceph_queue_inode_work(inode, CEPH_I_WORK_CHECK_CAPS);
}

static inline void ceph_queue_flush_snaps(struct inode *inode)
{
	ceph_queue_inode_work(inode, CEPH_I_WORK_FLUSH_SNAPS);
}

extern int __ceph_do_getattr(struct inode *inode, struct page *locked_page,
			     int mask, bool force);
static inline int ceph_do_getattr(struct inode *inode, int mask, bool force)
@@ -1105,6 +1132,7 @@ extern void ceph_take_cap_refs(struct ceph_inode_info *ci, int caps,
				bool snap_rwsem_locked);
extern void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps);
extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had);
extern void ceph_put_cap_refs_async(struct ceph_inode_info *ci, int had);
extern void ceph_put_cap_refs_no_check_caps(struct ceph_inode_info *ci,
					    int had);
extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
Loading