Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f9e5df2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ceph bug-fixes from Sage Weil:
 "These include a couple fixes to the new fscache code that went in
  during the last cycle (which will need to go stable@ shortly as well),
  a couple client-side directory fragmentation fixes, a fix for a race
  in the cap release queuing path, and a couple race fixes in the
  request abort and resend code.

  Obviously some of this could have gone into 3.12 final, but I
  preferred to overtest rather than send things in for a late -rc, and
  then my travel schedule intervened"

* 'for-linus-bugs' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client:
  ceph: allocate non-zero page to fscache in readpage()
  ceph: wake up 'safe' waiters when unregistering request
  ceph: cleanup aborted requests when re-sending requests.
  ceph: handle race between cap reconnect and cap release
  ceph: set caps count after composing cap reconnect message
  ceph: queue cap release in __ceph_remove_cap()
  ceph: handle frag mismatch between readdir request and reply
  ceph: remove outdated frag information
  ceph: hung on ceph fscache invalidate in some cases
parents 0e4b0743 ff638b7d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -216,7 +216,7 @@ static int readpage_nounlock(struct file *filp, struct page *page)
	}
	SetPageUptodate(page);

	if (err == 0)
	if (err >= 0)
		ceph_readpage_to_fscache(inode, page);

out:
+3 −0
Original line number Diff line number Diff line
@@ -324,6 +324,9 @@ void ceph_invalidate_fscache_page(struct inode* inode, struct page *page)
{
	struct ceph_inode_info *ci = ceph_inode(inode);

	if (!PageFsCache(page))
		return;

	fscache_wait_on_page_write(ci->fscache, page);
	fscache_uncache_page(ci->fscache, page);
}
+17 −10
Original line number Diff line number Diff line
@@ -897,7 +897,7 @@ static int __ceph_is_any_caps(struct ceph_inode_info *ci)
 * caller should hold i_ceph_lock.
 * caller will not hold session s_mutex if called from destroy_inode.
 */
void __ceph_remove_cap(struct ceph_cap *cap)
void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release)
{
	struct ceph_mds_session *session = cap->session;
	struct ceph_inode_info *ci = cap->ci;
@@ -909,6 +909,16 @@ void __ceph_remove_cap(struct ceph_cap *cap)

	/* remove from session list */
	spin_lock(&session->s_cap_lock);
	/*
	 * s_cap_reconnect is protected by s_cap_lock. no one changes
	 * s_cap_gen while session is in the reconnect state.
	 */
	if (queue_release &&
	    (!session->s_cap_reconnect ||
	     cap->cap_gen == session->s_cap_gen))
		__queue_cap_release(session, ci->i_vino.ino, cap->cap_id,
				    cap->mseq, cap->issue_seq);

	if (session->s_cap_iterator == cap) {
		/* not yet, we are iterating over this very cap */
		dout("__ceph_remove_cap  delaying %p removal from session %p\n",
@@ -1023,7 +1033,6 @@ void __queue_cap_release(struct ceph_mds_session *session,
	struct ceph_mds_cap_release *head;
	struct ceph_mds_cap_item *item;

	spin_lock(&session->s_cap_lock);
	BUG_ON(!session->s_num_cap_releases);
	msg = list_first_entry(&session->s_cap_releases,
			       struct ceph_msg, list_head);
@@ -1052,7 +1061,6 @@ void __queue_cap_release(struct ceph_mds_session *session,
		     (int)CEPH_CAPS_PER_RELEASE,
		     (int)msg->front.iov_len);
	}
	spin_unlock(&session->s_cap_lock);
}

/*
@@ -1067,12 +1075,8 @@ void ceph_queue_caps_release(struct inode *inode)
	p = rb_first(&ci->i_caps);
	while (p) {
		struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
		struct ceph_mds_session *session = cap->session;

		__queue_cap_release(session, ceph_ino(inode), cap->cap_id,
				    cap->mseq, cap->issue_seq);
		p = rb_next(p);
		__ceph_remove_cap(cap);
		__ceph_remove_cap(cap, true);
	}
}

@@ -2791,7 +2795,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
			}
			spin_unlock(&mdsc->cap_dirty_lock);
		}
		__ceph_remove_cap(cap);
		__ceph_remove_cap(cap, false);
	}
	/* else, we already released it */

@@ -2931,9 +2935,12 @@ void ceph_handle_caps(struct ceph_mds_session *session,
	if (!inode) {
		dout(" i don't have ino %llx\n", vino.ino);

		if (op == CEPH_CAP_OP_IMPORT)
		if (op == CEPH_CAP_OP_IMPORT) {
			spin_lock(&session->s_cap_lock);
			__queue_cap_release(session, vino.ino, cap_id,
					    mseq, seq);
			spin_unlock(&session->s_cap_lock);
		}
		goto flush_cap_releases;
	}

+10 −1
Original line number Diff line number Diff line
@@ -352,8 +352,18 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
		}

		/* note next offset and last dentry name */
		rinfo = &req->r_reply_info;
		if (le32_to_cpu(rinfo->dir_dir->frag) != frag) {
			frag = le32_to_cpu(rinfo->dir_dir->frag);
			if (ceph_frag_is_leftmost(frag))
				fi->next_offset = 2;
			else
				fi->next_offset = 0;
			off = fi->next_offset;
		}
		fi->offset = fi->next_offset;
		fi->last_readdir = req;
		fi->frag = frag;

		if (req->r_reply_info.dir_end) {
			kfree(fi->last_name);
@@ -363,7 +373,6 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
			else
				fi->next_offset = 0;
		} else {
			rinfo = &req->r_reply_info;
			err = note_last_dentry(fi,
				       rinfo->dir_dname[rinfo->dir_nr-1],
				       rinfo->dir_dname_len[rinfo->dir_nr-1]);
+43 −6
Original line number Diff line number Diff line
@@ -577,6 +577,8 @@ static int fill_inode(struct inode *inode,
	int issued = 0, implemented;
	struct timespec mtime, atime, ctime;
	u32 nsplits;
	struct ceph_inode_frag *frag;
	struct rb_node *rb_node;
	struct ceph_buffer *xattr_blob = NULL;
	int err = 0;
	int queue_trunc = 0;
@@ -751,15 +753,38 @@ static int fill_inode(struct inode *inode,
	/* FIXME: move me up, if/when version reflects fragtree changes */
	nsplits = le32_to_cpu(info->fragtree.nsplits);
	mutex_lock(&ci->i_fragtree_mutex);
	rb_node = rb_first(&ci->i_fragtree);
	for (i = 0; i < nsplits; i++) {
		u32 id = le32_to_cpu(info->fragtree.splits[i].frag);
		struct ceph_inode_frag *frag = __get_or_create_frag(ci, id);

		frag = NULL;
		while (rb_node) {
			frag = rb_entry(rb_node, struct ceph_inode_frag, node);
			if (ceph_frag_compare(frag->frag, id) >= 0) {
				if (frag->frag != id)
					frag = NULL;
				else
					rb_node = rb_next(rb_node);
				break;
			}
			rb_node = rb_next(rb_node);
			rb_erase(&frag->node, &ci->i_fragtree);
			kfree(frag);
			frag = NULL;
		}
		if (!frag) {
			frag = __get_or_create_frag(ci, id);
			if (IS_ERR(frag))
				continue;
		}
		frag->split_by = le32_to_cpu(info->fragtree.splits[i].by);
		dout(" frag %x split by %d\n", frag->frag, frag->split_by);
	}
	while (rb_node) {
		frag = rb_entry(rb_node, struct ceph_inode_frag, node);
		rb_node = rb_next(rb_node);
		rb_erase(&frag->node, &ci->i_fragtree);
		kfree(frag);
	}
	mutex_unlock(&ci->i_fragtree_mutex);

	/* were we issued a capability? */
@@ -1250,8 +1275,20 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
	int err = 0, i;
	struct inode *snapdir = NULL;
	struct ceph_mds_request_head *rhead = req->r_request->front.iov_base;
	u64 frag = le32_to_cpu(rhead->args.readdir.frag);
	struct ceph_dentry_info *di;
	u64 r_readdir_offset = req->r_readdir_offset;
	u32 frag = le32_to_cpu(rhead->args.readdir.frag);

	if (rinfo->dir_dir &&
	    le32_to_cpu(rinfo->dir_dir->frag) != frag) {
		dout("readdir_prepopulate got new frag %x -> %x\n",
		     frag, le32_to_cpu(rinfo->dir_dir->frag));
		frag = le32_to_cpu(rinfo->dir_dir->frag);
		if (ceph_frag_is_leftmost(frag))
			r_readdir_offset = 2;
		else
			r_readdir_offset = 0;
	}

	if (req->r_aborted)
		return readdir_prepopulate_inodes_only(req, session);
@@ -1315,7 +1352,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
		}

		di = dn->d_fsdata;
		di->offset = ceph_make_fpos(frag, i + req->r_readdir_offset);
		di->offset = ceph_make_fpos(frag, i + r_readdir_offset);

		/* inode */
		if (dn->d_inode) {
Loading