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

Commit 8d7a8fe2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ceph fixes from Sage Weil:
 "There is a pair of fixes for double-frees in the recent bundle for
  3.10, a couple of fixes for long-standing bugs (sleep while atomic and
  an endianness fix), and a locking fix that can be triggered when osds
  are going down"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client:
  rbd: fix cleanup in rbd_add()
  rbd: don't destroy ceph_opts in rbd_add()
  ceph: ceph_pagelist_append might sleep while atomic
  ceph: add cpu_to_le32() calls when encoding a reconnect capability
  libceph: must hold mutex for reset_changed_osds()
parents 77293e21 3abef3b3
Loading
Loading
Loading
Loading
+18 −15
Original line number Diff line number Diff line
@@ -519,8 +519,8 @@ static const struct block_device_operations rbd_bd_ops = {
};

/*
 * Initialize an rbd client instance.
 * We own *ceph_opts.
 * Initialize an rbd client instance.  Success or not, this function
 * consumes ceph_opts.
 */
static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts)
{
@@ -675,7 +675,8 @@ static int parse_rbd_opts_token(char *c, void *private)

/*
 * Get a ceph client with specific addr and configuration, if one does
 * not exist create it.
 * not exist create it.  Either way, ceph_opts is consumed by this
 * function.
 */
static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts)
{
@@ -4697,8 +4698,10 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev)
	return ret;
}

/* Undo whatever state changes are made by v1 or v2 image probe */

/*
 * Undo whatever state changes are made by v1 or v2 header info
 * call.
 */
static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
{
	struct rbd_image_header	*header;
@@ -4902,9 +4905,10 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping)
	int tmp;

	/*
	 * Get the id from the image id object.  If it's not a
	 * format 2 image, we'll get ENOENT back, and we'll assume
	 * it's a format 1 image.
	 * Get the id from the image id object.  Unless there's an
	 * error, rbd_dev->spec->image_id will be filled in with
	 * a dynamically-allocated string, and rbd_dev->image_format
	 * will be set to either 1 or 2.
	 */
	ret = rbd_dev_image_id(rbd_dev);
	if (ret)
@@ -4992,7 +4996,6 @@ static ssize_t rbd_add(struct bus_type *bus,
		rc = PTR_ERR(rbdc);
		goto err_out_args;
	}
	ceph_opts = NULL;	/* rbd_dev client now owns this */

	/* pick the pool */
	osdc = &rbdc->client->osdc;
@@ -5027,18 +5030,18 @@ static ssize_t rbd_add(struct bus_type *bus,
	rbd_dev->mapping.read_only = read_only;

	rc = rbd_dev_device_setup(rbd_dev);
	if (!rc)
	if (rc) {
		rbd_dev_image_release(rbd_dev);
		goto err_out_module;
	}

	return count;

	rbd_dev_image_release(rbd_dev);
err_out_rbd_dev:
	rbd_dev_destroy(rbd_dev);
err_out_client:
	rbd_put_client(rbdc);
err_out_args:
	if (ceph_opts)
		ceph_destroy_options(ceph_opts);
	kfree(rbd_opts);
	rbd_spec_put(spec);
err_out_module:
	module_put(THIS_MODULE);
+47 −26
Original line number Diff line number Diff line
@@ -191,27 +191,23 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
}

/**
 * Encode the flock and fcntl locks for the given inode into the pagelist.
 * Format is: #fcntl locks, sequential fcntl locks, #flock locks,
 * sequential flock locks.
 * Must be called with lock_flocks() already held.
 * If we encounter more of a specific lock type than expected,
 * we return the value 1.
 * Encode the flock and fcntl locks for the given inode into the ceph_filelock
 * array. Must be called with lock_flocks() already held.
 * If we encounter more of a specific lock type than expected, return -ENOSPC.
 */
int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
int ceph_encode_locks_to_buffer(struct inode *inode,
				struct ceph_filelock *flocks,
				int num_fcntl_locks, int num_flock_locks)
{
	struct file_lock *lock;
	struct ceph_filelock cephlock;
	int err = 0;
	int seen_fcntl = 0;
	int seen_flock = 0;
	int l = 0;

	dout("encoding %d flock and %d fcntl locks", num_flock_locks,
	     num_fcntl_locks);
	err = ceph_pagelist_append(pagelist, &num_fcntl_locks, sizeof(u32));
	if (err)
		goto fail;

	for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
		if (lock->fl_flags & FL_POSIX) {
			++seen_fcntl;
@@ -219,19 +215,12 @@ int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
				err = -ENOSPC;
				goto fail;
			}
			err = lock_to_ceph_filelock(lock, &cephlock);
			err = lock_to_ceph_filelock(lock, &flocks[l]);
			if (err)
				goto fail;
			err = ceph_pagelist_append(pagelist, &cephlock,
					   sizeof(struct ceph_filelock));
			++l;
		}
		if (err)
			goto fail;
	}

	err = ceph_pagelist_append(pagelist, &num_flock_locks, sizeof(u32));
	if (err)
		goto fail;
	for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
		if (lock->fl_flags & FL_FLOCK) {
			++seen_flock;
@@ -239,19 +228,51 @@ int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
				err = -ENOSPC;
				goto fail;
			}
			err = lock_to_ceph_filelock(lock, &cephlock);
			err = lock_to_ceph_filelock(lock, &flocks[l]);
			if (err)
				goto fail;
			err = ceph_pagelist_append(pagelist, &cephlock,
					   sizeof(struct ceph_filelock));
			++l;
		}
		if (err)
			goto fail;
	}
fail:
	return err;
}

/**
 * Copy the encoded flock and fcntl locks into the pagelist.
 * Format is: #fcntl locks, sequential fcntl locks, #flock locks,
 * sequential flock locks.
 * Returns zero on success.
 */
int ceph_locks_to_pagelist(struct ceph_filelock *flocks,
			   struct ceph_pagelist *pagelist,
			   int num_fcntl_locks, int num_flock_locks)
{
	int err = 0;
	__le32 nlocks;

	nlocks = cpu_to_le32(num_fcntl_locks);
	err = ceph_pagelist_append(pagelist, &nlocks, sizeof(nlocks));
	if (err)
		goto out_fail;

	err = ceph_pagelist_append(pagelist, flocks,
				   num_fcntl_locks * sizeof(*flocks));
	if (err)
		goto out_fail;

	nlocks = cpu_to_le32(num_flock_locks);
	err = ceph_pagelist_append(pagelist, &nlocks, sizeof(nlocks));
	if (err)
		goto out_fail;

	err = ceph_pagelist_append(pagelist,
				   &flocks[num_fcntl_locks],
				   num_flock_locks * sizeof(*flocks));
out_fail:
	return err;
}

/*
 * Given a pointer to a lock, convert it to a ceph filelock
 */
+35 −30
Original line number Diff line number Diff line
@@ -2478,39 +2478,44 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,

	if (recon_state->flock) {
		int num_fcntl_locks, num_flock_locks;
		struct ceph_pagelist_cursor trunc_point;
		struct ceph_filelock *flocks;

		ceph_pagelist_set_cursor(pagelist, &trunc_point);
		do {
encode_again:
		lock_flocks();
			ceph_count_locks(inode, &num_fcntl_locks,
					 &num_flock_locks);
			rec.v2.flock_len = (2*sizeof(u32) +
					    (num_fcntl_locks+num_flock_locks) *
					    sizeof(struct ceph_filelock));
		ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
		unlock_flocks();

			/* pre-alloc pagelist */
			ceph_pagelist_truncate(pagelist, &trunc_point);
			err = ceph_pagelist_append(pagelist, &rec, reclen);
			if (!err)
				err = ceph_pagelist_reserve(pagelist,
							    rec.v2.flock_len);

			/* encode locks */
			if (!err) {
		flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
				 sizeof(struct ceph_filelock), GFP_NOFS);
		if (!flocks) {
			err = -ENOMEM;
			goto out_free;
		}
		lock_flocks();
				err = ceph_encode_locks(inode,
							pagelist,
		err = ceph_encode_locks_to_buffer(inode, flocks,
						  num_fcntl_locks,
						  num_flock_locks);
		unlock_flocks();
		if (err) {
			kfree(flocks);
			if (err == -ENOSPC)
				goto encode_again;
			goto out_free;
		}
		} while (err == -ENOSPC);
		/*
		 * number of encoded locks is stable, so copy to pagelist
		 */
		rec.v2.flock_len = cpu_to_le32(2*sizeof(u32) +
				    (num_fcntl_locks+num_flock_locks) *
				    sizeof(struct ceph_filelock));
		err = ceph_pagelist_append(pagelist, &rec, reclen);
		if (!err)
			err = ceph_locks_to_pagelist(flocks, pagelist,
						     num_fcntl_locks,
						     num_flock_locks);
		kfree(flocks);
	} else {
		err = ceph_pagelist_append(pagelist, &rec, reclen);
	}

out_free:
	kfree(path);
out_dput:
+7 −2
Original line number Diff line number Diff line
@@ -822,8 +822,13 @@ extern const struct export_operations ceph_export_ops;
extern int ceph_lock(struct file *file, int cmd, struct file_lock *fl);
extern int ceph_flock(struct file *file, int cmd, struct file_lock *fl);
extern void ceph_count_locks(struct inode *inode, int *p_num, int *f_num);
extern int ceph_encode_locks(struct inode *i, struct ceph_pagelist *p,
			     int p_locks, int f_locks);
extern int ceph_encode_locks_to_buffer(struct inode *inode,
				       struct ceph_filelock *flocks,
				       int num_fcntl_locks,
				       int num_flock_locks);
extern int ceph_locks_to_pagelist(struct ceph_filelock *flocks,
				  struct ceph_pagelist *pagelist,
				  int num_fcntl_locks, int num_flock_locks);
extern int lock_to_ceph_filelock(struct file_lock *fl, struct ceph_filelock *c);

/* debugfs.c */
+1 −1
Original line number Diff line number Diff line
@@ -1675,13 +1675,13 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
		__register_request(osdc, req);
		__unregister_linger_request(osdc, req);
	}
	reset_changed_osds(osdc);
	mutex_unlock(&osdc->request_mutex);

	if (needmap) {
		dout("%d requests for down osds, need new map\n", needmap);
		ceph_monc_request_next_osdmap(&osdc->client->monc);
	}
	reset_changed_osds(osdc);
}