Commit fcbf68d3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ceph-for-7.1-rc4' of https://github.com/ceph/ceph-client

Pull ceph fixes from Ilya Dryomov:
 "An important patch from Hristo that squashes a folio reference leak
  that could lead to OOM kills in CephFS and a number of miscellaneous
  fixes from Raphael and Slava.

  All but two are marked for stable"

* tag 'ceph-for-7.1-rc4' of https://github.com/ceph/ceph-client:
  libceph: Fix potential null-ptr-deref in decode_choose_args()
  libceph: handle rbtree insertion error in decode_choose_args()
  libceph: Fix potential out-of-bounds access in osdmap_decode()
  ceph: put folios not suitable for writeback
  ceph: add ceph_has_realms_with_quotas() check to ceph_quota_update_statfs()
  libceph: Fix potential out-of-bounds access in __ceph_x_decrypt()
  ceph: fix BUG_ON in __ceph_build_xattrs_blob() due to stale blob size
  ceph: fix a buffer leak in __ceph_setxattr()
  libceph: Fix unnecessarily high ceph_decode_need() for uniform bucket
  libceph: Fix potential out-of-bounds access in crush_decode()
parents a8b0b722 28b0a2ab
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1336,6 +1336,7 @@ void ceph_process_folio_batch(struct address_space *mapping,
						  ceph_wbc, folio);
		if (rc == -ENODATA) {
			folio_unlock(folio);
			folio_put(folio);
			ceph_wbc->fbatch.folios[i] = NULL;
			continue;
		} else if (rc == -E2BIG) {
@@ -1346,6 +1347,7 @@ void ceph_process_folio_batch(struct address_space *mapping,
		if (!folio_clear_dirty_for_io(folio)) {
			doutc(cl, "%p !folio_clear_dirty_for_io\n", folio);
			folio_unlock(folio);
			folio_put(folio);
			ceph_wbc->fbatch.folios[i] = NULL;
			continue;
		}
+27 −10
Original line number Diff line number Diff line
@@ -228,12 +228,19 @@ static int get_quota_realm(struct ceph_mds_client *mdsc, struct inode *inode,

restart:
	realm = ceph_inode(inode)->i_snap_realm;
	if (realm)
	if (realm) {
		ceph_get_snap_realm(mdsc, realm);
	else
		pr_err_ratelimited_client(cl,
				"%p %llx.%llx null i_snap_realm\n",
	} else {
		/*
		 * i_snap_realm is NULL when all caps have been released, e.g.
		 * after an MDS session rejection. This is a transient state;
		 * the realm will be restored once caps are re-granted.
		 * Treat it as "no quota realm found".
		 */
		doutc(cl, "%p %llx.%llx null i_snap_realm\n",
		      inode, ceph_vinop(inode));
	}

	while (realm) {
		bool has_inode;

@@ -340,12 +347,19 @@ static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
	down_read(&mdsc->snap_rwsem);
restart:
	realm = ceph_inode(inode)->i_snap_realm;
	if (realm)
	if (realm) {
		ceph_get_snap_realm(mdsc, realm);
	else
		pr_err_ratelimited_client(cl,
				"%p %llx.%llx null i_snap_realm\n",
	} else {
		/*
		 * i_snap_realm is NULL when all caps have been released, e.g.
		 * after an MDS session rejection. This is a transient state;
		 * the realm will be restored once caps are re-granted.
		 * Treat it as "quota not exceeded".
		 */
		doutc(cl, "%p %llx.%llx null i_snap_realm\n",
		      inode, ceph_vinop(inode));
	}

	while (realm) {
		bool has_inode;

@@ -496,6 +510,9 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
	u64 total = 0, used, free;
	bool is_updated = false;

	if (!ceph_has_realms_with_quotas(d_inode(fsc->sb->s_root)))
		return false;

	down_read(&mdsc->snap_rwsem);
	get_quota_realm(mdsc, d_inode(fsc->sb->s_root), QUOTA_GET_MAX_BYTES,
			&realm, true);
+17 −0
Original line number Diff line number Diff line
@@ -1254,6 +1254,22 @@ int __ceph_setxattr(struct inode *inode, const char *name,
	      ceph_vinop(inode), name, ceph_cap_string(issued));
	__build_xattrs(inode);

	/*
	 * __build_xattrs() may have released and reacquired i_ceph_lock,
	 * during which handle_cap_grant() could have replaced i_xattrs.blob
	 * with a newer MDS-provided blob and bumped i_xattrs.version. If that
	 * caused __build_xattrs() to rebuild the rb-tree from the new blob,
	 * count/names_size/vals_size may now be larger than when
	 * required_blob_size was computed above. Recompute it here so the
	 * prealloc_blob size check below reflects the current tree state.
	 */
	required_blob_size = __get_required_blob_size(ci, name_len, val_len);
	if (required_blob_size > mdsc->mdsmap->m_max_xattr_size) {
		doutc(cl, "sync (size too large): %d > %llu\n",
		      required_blob_size, mdsc->mdsmap->m_max_xattr_size);
		goto do_sync;
	}

	if (!ci->i_xattrs.prealloc_blob ||
	    required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
		struct ceph_buffer *blob;
@@ -1294,6 +1310,7 @@ int __ceph_setxattr(struct inode *inode, const char *name,

do_sync:
	spin_unlock(&ci->i_ceph_lock);
	ceph_buffer_put(old_blob);
do_sync_unlocked:
	if (lock_snap_rwsem)
		up_read(&mdsc->snap_rwsem);
+5 −0
Original line number Diff line number Diff line
@@ -115,6 +115,11 @@ static int __ceph_x_decrypt(const struct ceph_crypto_key *key, int usage_slot,
	if (ret)
		return ret;

	if (plaintext_len < sizeof(*hdr)) {
		pr_err("%s plaintext too small %d\n", __func__, plaintext_len);
		return -EINVAL;
	}

	hdr = p + ceph_crypt_data_offset(key);
	if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) {
		pr_err("%s bad magic\n", __func__);
+1 −5
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ int crush_get_bucket_item_weight(const struct crush_bucket *b, int p)
void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
{
	kfree(b->h.items);
	kfree(b);
}

void crush_destroy_bucket_list(struct crush_bucket_list *b)
@@ -55,14 +54,12 @@ void crush_destroy_bucket_list(struct crush_bucket_list *b)
	kfree(b->item_weights);
	kfree(b->sum_weights);
	kfree(b->h.items);
	kfree(b);
}

void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
{
	kfree(b->h.items);
	kfree(b->node_weights);
	kfree(b);
}

void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
@@ -70,14 +67,12 @@ void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
	kfree(b->straws);
	kfree(b->item_weights);
	kfree(b->h.items);
	kfree(b);
}

void crush_destroy_bucket_straw2(struct crush_bucket_straw2 *b)
{
	kfree(b->item_weights);
	kfree(b->h.items);
	kfree(b);
}

void crush_destroy_bucket(struct crush_bucket *b)
@@ -99,6 +94,7 @@ void crush_destroy_bucket(struct crush_bucket *b)
		crush_destroy_bucket_straw2((struct crush_bucket_straw2 *)b);
		break;
	}
	kfree(b);
}

/**
Loading