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

Commit 2833419a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ceph-for-4.16-rc4' of git://github.com/ceph/ceph-client

Pull ceph fixes from Ilya Dryomov:
 "A cap handling fix from Zhi that ensures that metadata writeback isn't
  delayed and three error path memory leak fixups from Chengguang"

* tag 'ceph-for-4.16-rc4' of git://github.com/ceph/ceph-client:
  ceph: fix potential memory leak in init_caches()
  ceph: fix dentry leak when failing to init debugfs
  libceph, ceph: avoid memory leak when specifying same option several times
  ceph: flush dirty caps of unlinked inode ASAP
parents fb6d47a5 1c789249
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -3964,6 +3964,32 @@ void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
		ceph_check_caps(ci, 0, NULL);
}

/*
 * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps. If it
 * looks like the link count will hit 0, drop any other caps (other
 * than PIN) we don't specifically want (due to the file still being
 * open).
 */
int ceph_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(&ci->i_ceph_lock);
	if (inode->i_nlink == 1) {
		drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);

		ci->i_ceph_flags |= CEPH_I_NODELAY;
		if (__ceph_caps_dirty(ci)) {
			struct ceph_mds_client *mdsc =
				ceph_inode_to_client(inode)->mdsc;
			__cap_delay_requeue_front(mdsc, ci);
		}
	}
	spin_unlock(&ci->i_ceph_lock);
	return drop;
}

/*
 * Helpers for embedding cap and dentry lease releases into mds
 * requests.
+5 −23
Original line number Diff line number Diff line
@@ -1002,26 +1002,6 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
	return err;
}

/*
 * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps.  If it
 * looks like the link count will hit 0, drop any other caps (other
 * than PIN) we don't specifically want (due to the file still being
 * open).
 */
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(&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(&ci->i_ceph_lock);
	return drop;
}

/*
 * rmdir and unlink are differ only by the metadata op code
 */
@@ -1056,7 +1036,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
	set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
	req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
	req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
	req->r_inode_drop = drop_caps_for_unlink(inode);
	req->r_inode_drop = ceph_drop_caps_for_unlink(inode);
	err = ceph_mdsc_do_request(mdsc, dir, req);
	if (!err && !req->r_reply_info.head->is_dentry)
		d_delete(dentry);
@@ -1104,8 +1084,10 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
	req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
	/* release LINK_RDCACHE on source inode (mds will lock it) */
	req->r_old_inode_drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
	if (d_really_is_positive(new_dentry))
		req->r_inode_drop = drop_caps_for_unlink(d_inode(new_dentry));
	if (d_really_is_positive(new_dentry)) {
		req->r_inode_drop =
			ceph_drop_caps_for_unlink(d_inode(new_dentry));
	}
	err = ceph_mdsc_do_request(mdsc, old_dir, req);
	if (!err && !req->r_reply_info.head->is_dentry) {
		/*
+13 −14
Original line number Diff line number Diff line
@@ -225,6 +225,7 @@ static int parse_fsopt_token(char *c, void *private)
			return -ENOMEM;
		break;
	case Opt_mds_namespace:
		kfree(fsopt->mds_namespace);
		fsopt->mds_namespace = kstrndup(argstr[0].from,
						argstr[0].to-argstr[0].from,
						GFP_KERNEL);
@@ -232,6 +233,7 @@ static int parse_fsopt_token(char *c, void *private)
			return -ENOMEM;
		break;
	case Opt_fscache_uniq:
		kfree(fsopt->fscache_uniq);
		fsopt->fscache_uniq = kstrndup(argstr[0].from,
					       argstr[0].to-argstr[0].from,
					       GFP_KERNEL);
@@ -711,14 +713,17 @@ static int __init init_caches(void)
		goto bad_dentry;

	ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD);

	if (!ceph_file_cachep)
		goto bad_file;

	if ((error = ceph_fscache_register()))
		goto bad_file;
	error = ceph_fscache_register();
	if (error)
		goto bad_fscache;

	return 0;

bad_fscache:
	kmem_cache_destroy(ceph_file_cachep);
bad_file:
	kmem_cache_destroy(ceph_dentry_cachep);
bad_dentry:
@@ -836,7 +841,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
	int err;
	unsigned long started = jiffies;  /* note the start time */
	struct dentry *root;
	int first = 0;   /* first vfsmount for this super_block */

	dout("mount start %p\n", fsc);
	mutex_lock(&fsc->client->mount_mutex);
@@ -861,17 +865,17 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
			path = fsc->mount_options->server_path + 1;
			dout("mount opening path %s\n", path);
		}

		err = ceph_fs_debugfs_init(fsc);
		if (err < 0)
			goto out;

		root = open_root_dentry(fsc, path, started);
		if (IS_ERR(root)) {
			err = PTR_ERR(root);
			goto out;
		}
		fsc->sb->s_root = dget(root);
		first = 1;

		err = ceph_fs_debugfs_init(fsc);
		if (err < 0)
			goto fail;
	} else {
		root = dget(fsc->sb->s_root);
	}
@@ -881,11 +885,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
	mutex_unlock(&fsc->client->mount_mutex);
	return root;

fail:
	if (first) {
		dput(fsc->sb->s_root);
		fsc->sb->s_root = NULL;
	}
out:
	mutex_unlock(&fsc->client->mount_mutex);
	return ERR_PTR(err);
+1 −1
Original line number Diff line number Diff line
@@ -987,7 +987,7 @@ extern void ceph_check_caps(struct ceph_inode_info *ci, int flags,
			    struct ceph_mds_session *session);
extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc);
extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc);

extern int  ceph_drop_caps_for_unlink(struct inode *inode);
extern int ceph_encode_inode_release(void **p, struct inode *inode,
				     int mds, int drop, int unless, int force);
extern int ceph_encode_dentry_release(void **p, struct dentry *dn,
+7 −0
Original line number Diff line number Diff line
@@ -418,6 +418,7 @@ ceph_parse_options(char *options, const char *dev_name,
				opt->flags |= CEPH_OPT_FSID;
			break;
		case Opt_name:
			kfree(opt->name);
			opt->name = kstrndup(argstr[0].from,
					      argstr[0].to-argstr[0].from,
					      GFP_KERNEL);
@@ -427,6 +428,9 @@ ceph_parse_options(char *options, const char *dev_name,
			}
			break;
		case Opt_secret:
			ceph_crypto_key_destroy(opt->key);
			kfree(opt->key);

		        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
			if (!opt->key) {
				err = -ENOMEM;
@@ -437,6 +441,9 @@ ceph_parse_options(char *options, const char *dev_name,
				goto out;
			break;
		case Opt_key:
			ceph_crypto_key_destroy(opt->key);
			kfree(opt->key);

		        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
			if (!opt->key) {
				err = -ENOMEM;