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

Commit 7d8cb26d authored by Sage Weil's avatar Sage Weil
Browse files

ceph: maintain i_head_snapc when any caps are dirty, not just for data



We used to use i_head_snapc to keep track of which snapc the current epoch
of dirty data was dirtied under.  It is used by queue_cap_snap to set up
the cap_snap.  However, since we queue cap snaps for any dirty caps, not
just for dirty file data, we need to keep a valid i_head_snapc anytime
we have dirty|flushing caps.  This fixes a NULL pointer deref in
queue_cap_snap when writing back dirty caps without data (e.g.,
snaptest-authwb.sh).

Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 07a27e22
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -87,7 +87,7 @@ static int ceph_set_page_dirty(struct page *page)


	/* dirty the head */
	/* dirty the head */
	spin_lock(&inode->i_lock);
	spin_lock(&inode->i_lock);
	if (ci->i_wrbuffer_ref_head == 0)
	if (ci->i_head_snapc == NULL)
		ci->i_head_snapc = ceph_get_snap_context(snapc);
		ci->i_head_snapc = ceph_get_snap_context(snapc);
	++ci->i_wrbuffer_ref_head;
	++ci->i_wrbuffer_ref_head;
	if (ci->i_wrbuffer_ref == 0)
	if (ci->i_wrbuffer_ref == 0)
@@ -346,7 +346,7 @@ static struct ceph_snap_context *get_oldest_context(struct inode *inode,
			break;
			break;
		}
		}
	}
	}
	if (!snapc && ci->i_head_snapc) {
	if (!snapc && ci->i_wrbuffer_ref_head) {
		snapc = ceph_get_snap_context(ci->i_head_snapc);
		snapc = ceph_get_snap_context(ci->i_head_snapc);
		dout(" head snapc %p has %d dirty pages\n",
		dout(" head snapc %p has %d dirty pages\n",
		     snapc, ci->i_wrbuffer_ref_head);
		     snapc, ci->i_wrbuffer_ref_head);
+17 −3
Original line number Original line Diff line number Diff line
@@ -1143,6 +1143,10 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
		for (i = 0; i < CEPH_CAP_BITS; i++)
		for (i = 0; i < CEPH_CAP_BITS; i++)
			if (flushing & (1 << i))
			if (flushing & (1 << i))
				ci->i_cap_flush_tid[i] = flush_tid;
				ci->i_cap_flush_tid[i] = flush_tid;

		follows = ci->i_head_snapc->seq;
	} else {
		follows = 0;
	}
	}


	keep = cap->implemented;
	keep = cap->implemented;
@@ -1156,7 +1160,6 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
	mtime = inode->i_mtime;
	mtime = inode->i_mtime;
	atime = inode->i_atime;
	atime = inode->i_atime;
	time_warp_seq = ci->i_time_warp_seq;
	time_warp_seq = ci->i_time_warp_seq;
	follows = ci->i_snap_realm->cached_context->seq;
	uid = inode->i_uid;
	uid = inode->i_uid;
	gid = inode->i_gid;
	gid = inode->i_gid;
	mode = inode->i_mode;
	mode = inode->i_mode;
@@ -1332,7 +1335,11 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
	     ceph_cap_string(was | mask));
	     ceph_cap_string(was | mask));
	ci->i_dirty_caps |= mask;
	ci->i_dirty_caps |= mask;
	if (was == 0) {
	if (was == 0) {
		dout(" inode %p now dirty\n", &ci->vfs_inode);
		if (!ci->i_head_snapc)
			ci->i_head_snapc = ceph_get_snap_context(
				ci->i_snap_realm->cached_context);
		dout(" inode %p now dirty snapc %p\n", &ci->vfs_inode,
			ci->i_head_snapc);
		BUG_ON(!list_empty(&ci->i_dirty_item));
		BUG_ON(!list_empty(&ci->i_dirty_item));
		spin_lock(&mdsc->cap_dirty_lock);
		spin_lock(&mdsc->cap_dirty_lock);
		list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
		list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
@@ -2190,7 +2197,9 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,


	if (ci->i_head_snapc == snapc) {
	if (ci->i_head_snapc == snapc) {
		ci->i_wrbuffer_ref_head -= nr;
		ci->i_wrbuffer_ref_head -= nr;
		if (!ci->i_wrbuffer_ref_head) {
		if (ci->i_wrbuffer_ref_head == 0 &&
		    ci->i_dirty_caps == 0 && ci->i_flushing_caps == 0) {
			BUG_ON(!ci->i_head_snapc);
			ceph_put_snap_context(ci->i_head_snapc);
			ceph_put_snap_context(ci->i_head_snapc);
			ci->i_head_snapc = NULL;
			ci->i_head_snapc = NULL;
		}
		}
@@ -2483,6 +2492,11 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
			dout(" inode %p now clean\n", inode);
			dout(" inode %p now clean\n", inode);
			BUG_ON(!list_empty(&ci->i_dirty_item));
			BUG_ON(!list_empty(&ci->i_dirty_item));
			drop = 1;
			drop = 1;
			if (ci->i_wrbuffer_ref_head == 0) {
				BUG_ON(!ci->i_head_snapc);
				ceph_put_snap_context(ci->i_head_snapc);
				ci->i_head_snapc = NULL;
			}
		} else {
		} else {
			BUG_ON(list_empty(&ci->i_dirty_item));
			BUG_ON(list_empty(&ci->i_dirty_item));
		}
		}
+5 −1
Original line number Original line Diff line number Diff line
@@ -458,6 +458,8 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
			     CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR))) {
			     CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR))) {
		struct ceph_snap_context *snapc = ci->i_head_snapc;
		struct ceph_snap_context *snapc = ci->i_head_snapc;


		dout("queue_cap_snap %p cap_snap %p queuing under %p\n", inode,
		     capsnap, snapc);
		igrab(inode);
		igrab(inode);
		
		
		atomic_set(&capsnap->nref, 1);
		atomic_set(&capsnap->nref, 1);
@@ -489,7 +491,9 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
		capsnap->dirty_pages = ci->i_wrbuffer_ref_head;
		capsnap->dirty_pages = ci->i_wrbuffer_ref_head;
		ci->i_wrbuffer_ref_head = 0;
		ci->i_wrbuffer_ref_head = 0;
		capsnap->context = snapc;
		capsnap->context = snapc;
		ci->i_head_snapc = NULL;
		ci->i_head_snapc =
			ceph_get_snap_context(ci->i_snap_realm->cached_context);
		dout(" new snapc is %p\n", ci->i_head_snapc);
		list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps);
		list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps);


		if (used & CEPH_CAP_FILE_WR) {
		if (used & CEPH_CAP_FILE_WR) {
+2 −1
Original line number Original line Diff line number Diff line
@@ -344,7 +344,8 @@ struct ceph_inode_info {
	unsigned i_cap_exporting_issued;
	unsigned i_cap_exporting_issued;
	struct ceph_cap_reservation i_cap_migration_resv;
	struct ceph_cap_reservation i_cap_migration_resv;
	struct list_head i_cap_snaps;   /* snapped state pending flush to mds */
	struct list_head i_cap_snaps;   /* snapped state pending flush to mds */
	struct ceph_snap_context *i_head_snapc;  /* set if wr_buffer_head > 0 */
	struct ceph_snap_context *i_head_snapc;  /* set if wr_buffer_head > 0 or
						    dirty|flushing caps */
	unsigned i_snap_caps;           /* cap bits for snapped files */
	unsigned i_snap_caps;           /* cap bits for snapped files */


	int i_nr_by_mode[CEPH_FILE_MODE_NUM];  /* open file counts */
	int i_nr_by_mode[CEPH_FILE_MODE_NUM];  /* open file counts */