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

Commit be655596 authored by Sage Weil's avatar Sage Weil
Browse files

ceph: use i_ceph_lock instead of i_lock



We have been using i_lock to protect all kinds of data structures in the
ceph_inode_info struct, including lists of inodes that we need to iterate
over while avoiding races with inode destruction.  That requires grabbing
a reference to the inode with the list lock protected, but igrab() now
takes i_lock to check the inode flags.

Changing the list lock ordering would be a painful process.

However, using a ceph-specific i_ceph_lock in the ceph inode instead of
i_lock is a simple mechanical change and avoids the ordering constraints
imposed by igrab().

Reported-by: default avatarAmon Ott <a.ott@m-privacy.de>
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 51703306
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ static int ceph_set_page_dirty(struct page *page)
	snapc = ceph_get_snap_context(ci->i_snap_realm->cached_context);

	/* dirty the head */
	spin_lock(&inode->i_lock);
	spin_lock(&ci->i_ceph_lock);
	if (ci->i_head_snapc == NULL)
		ci->i_head_snapc = ceph_get_snap_context(snapc);
	++ci->i_wrbuffer_ref_head;
@@ -100,7 +100,7 @@ static int ceph_set_page_dirty(struct page *page)
	     ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref_head-1,
	     ci->i_wrbuffer_ref, ci->i_wrbuffer_ref_head,
	     snapc, snapc->seq, snapc->num_snaps);
	spin_unlock(&inode->i_lock);
	spin_unlock(&ci->i_ceph_lock);

	/* now adjust page */
	spin_lock_irq(&mapping->tree_lock);
@@ -391,7 +391,7 @@ static struct ceph_snap_context *get_oldest_context(struct inode *inode,
	struct ceph_snap_context *snapc = NULL;
	struct ceph_cap_snap *capsnap = NULL;

	spin_lock(&inode->i_lock);
	spin_lock(&ci->i_ceph_lock);
	list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
		dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap,
		     capsnap->context, capsnap->dirty_pages);
@@ -407,7 +407,7 @@ static struct ceph_snap_context *get_oldest_context(struct inode *inode,
		dout(" head snapc %p has %d dirty pages\n",
		     snapc, ci->i_wrbuffer_ref_head);
	}
	spin_unlock(&inode->i_lock);
	spin_unlock(&ci->i_ceph_lock);
	return snapc;
}

+94 −93

File changed.

Preview size limit exceeded, changes collapsed.

+12 −12
Original line number Diff line number Diff line
@@ -281,18 +281,18 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
	}

	/* can we use the dcache? */
	spin_lock(&inode->i_lock);
	spin_lock(&ci->i_ceph_lock);
	if ((filp->f_pos == 2 || fi->dentry) &&
	    !ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
	    ceph_snap(inode) != CEPH_SNAPDIR &&
	    ceph_dir_test_complete(inode) &&
	    __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
		spin_unlock(&inode->i_lock);
		spin_unlock(&ci->i_ceph_lock);
		err = __dcache_readdir(filp, dirent, filldir);
		if (err != -EAGAIN)
			return err;
	} else {
		spin_unlock(&inode->i_lock);
		spin_unlock(&ci->i_ceph_lock);
	}
	if (fi->dentry) {
		err = note_last_dentry(fi, fi->dentry->d_name.name,
@@ -428,12 +428,12 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
	 * were released during the whole readdir, and we should have
	 * the complete dir contents in our cache.
	 */
	spin_lock(&inode->i_lock);
	spin_lock(&ci->i_ceph_lock);
	if (ci->i_release_count == fi->dir_release_count) {
		ceph_dir_set_complete(inode);
		ci->i_max_offset = filp->f_pos;
	}
	spin_unlock(&inode->i_lock);
	spin_unlock(&ci->i_ceph_lock);

	dout("readdir %p filp %p done.\n", inode, filp);
	return 0;
@@ -607,7 +607,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
		struct ceph_inode_info *ci = ceph_inode(dir);
		struct ceph_dentry_info *di = ceph_dentry(dentry);

		spin_lock(&dir->i_lock);
		spin_lock(&ci->i_ceph_lock);
		dout(" dir %p flags are %d\n", dir, ci->i_ceph_flags);
		if (strncmp(dentry->d_name.name,
			    fsc->mount_options->snapdir_name,
@@ -615,13 +615,13 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
		    !is_root_ceph_dentry(dir, dentry) &&
		    ceph_dir_test_complete(dir) &&
		    (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
			spin_unlock(&dir->i_lock);
			spin_unlock(&ci->i_ceph_lock);
			dout(" dir %p complete, -ENOENT\n", dir);
			d_add(dentry, NULL);
			di->lease_shared_gen = ci->i_shared_gen;
			return NULL;
		}
		spin_unlock(&dir->i_lock);
		spin_unlock(&ci->i_ceph_lock);
	}

	op = ceph_snap(dir) == CEPH_SNAPDIR ?
@@ -841,12 +841,12 @@ static int drop_caps_for_unlink(struct inode *inode)
	struct ceph_inode_info *ci = ceph_inode(inode);
	int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;

	spin_lock(&inode->i_lock);
	spin_lock(&ci->i_ceph_lock);
	if (inode->i_nlink == 1) {
		drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);
		ci->i_ceph_flags |= CEPH_I_NODELAY;
	}
	spin_unlock(&inode->i_lock);
	spin_unlock(&ci->i_ceph_lock);
	return drop;
}

@@ -1015,10 +1015,10 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
	struct ceph_dentry_info *di = ceph_dentry(dentry);
	int valid = 0;

	spin_lock(&dir->i_lock);
	spin_lock(&ci->i_ceph_lock);
	if (ci->i_shared_gen == di->lease_shared_gen)
		valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
	spin_unlock(&dir->i_lock);
	spin_unlock(&ci->i_ceph_lock);
	dout("dir_lease_is_valid dir %p v%u dentry %p v%u = %d\n",
	     dir, (unsigned)ci->i_shared_gen, dentry,
	     (unsigned)di->lease_shared_gen, valid);
+10 −10
Original line number Diff line number Diff line
@@ -147,9 +147,9 @@ int ceph_open(struct inode *inode, struct file *file)

	/* trivially open snapdir */
	if (ceph_snap(inode) == CEPH_SNAPDIR) {
		spin_lock(&inode->i_lock);
		spin_lock(&ci->i_ceph_lock);
		__ceph_get_fmode(ci, fmode);
		spin_unlock(&inode->i_lock);
		spin_unlock(&ci->i_ceph_lock);
		return ceph_init_file(inode, file, fmode);
	}

@@ -158,7 +158,7 @@ int ceph_open(struct inode *inode, struct file *file)
	 * write) or any MDS (for read).  Update wanted set
	 * asynchronously.
	 */
	spin_lock(&inode->i_lock);
	spin_lock(&ci->i_ceph_lock);
	if (__ceph_is_any_real_caps(ci) &&
	    (((fmode & CEPH_FILE_MODE_WR) == 0) || ci->i_auth_cap)) {
		int mds_wanted = __ceph_caps_mds_wanted(ci);
@@ -168,7 +168,7 @@ int ceph_open(struct inode *inode, struct file *file)
		     inode, fmode, ceph_cap_string(wanted),
		     ceph_cap_string(issued));
		__ceph_get_fmode(ci, fmode);
		spin_unlock(&inode->i_lock);
		spin_unlock(&ci->i_ceph_lock);

		/* adjust wanted? */
		if ((issued & wanted) != wanted &&
@@ -180,10 +180,10 @@ 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);
		spin_unlock(&inode->i_lock);
		spin_unlock(&ci->i_ceph_lock);
		return ceph_init_file(inode, file, fmode);
	}
	spin_unlock(&inode->i_lock);
	spin_unlock(&ci->i_ceph_lock);

	dout("open fmode %d wants %s\n", fmode, ceph_cap_string(wanted));
	req = prepare_open_request(inode->i_sb, flags, 0);
@@ -743,9 +743,9 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
		 */
		int dirty;

		spin_lock(&inode->i_lock);
		spin_lock(&ci->i_ceph_lock);
		dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
		spin_unlock(&inode->i_lock);
		spin_unlock(&ci->i_ceph_lock);
		ceph_put_cap_refs(ci, got);

		ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
@@ -764,9 +764,9 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,

	if (ret >= 0) {
		int dirty;
		spin_lock(&inode->i_lock);
		spin_lock(&ci->i_ceph_lock);
		dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
		spin_unlock(&inode->i_lock);
		spin_unlock(&ci->i_ceph_lock);
		if (dirty)
			__mark_inode_dirty(inode, dirty);
	}
+28 −25

File changed.

Preview size limit exceeded, changes collapsed.

Loading