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

Merge tag 'ceph-for-5.6-rc2' of https://github.com/ceph/ceph-client

Pull ceph fixes from Ilya Dryomov:

 - make O_DIRECT | O_APPEND combination work better

 - redo the server path canonicalization patch that went into -rc1

 - fix the 'noacl' mount option that got broken by the conversion to the
   new mount API in 5.5

* tag 'ceph-for-5.6-rc2' of https://github.com/ceph/ceph-client:
  ceph: noacl mount option is effectively ignored
  ceph: canonicalize server path in place
  ceph: do not execute direct write in parallel if O_APPEND is specified
parents ca60ad6a 3b20bc2f
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -1418,6 +1418,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
	struct ceph_cap_flush *prealloc_cf;
	ssize_t count, written = 0;
	int err, want, got;
	bool direct_lock = false;
	loff_t pos;
	loff_t limit = max(i_size_read(inode), fsc->max_file_size);

@@ -1428,8 +1429,11 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
	if (!prealloc_cf)
		return -ENOMEM;

	if ((iocb->ki_flags & (IOCB_DIRECT | IOCB_APPEND)) == IOCB_DIRECT)
		direct_lock = true;

retry_snap:
	if (iocb->ki_flags & IOCB_DIRECT)
	if (direct_lock)
		ceph_start_io_direct(inode);
	else
		ceph_start_io_write(inode);
@@ -1519,14 +1523,15 @@ retry_snap:

		/* we might need to revert back to that point */
		data = *from;
		if (iocb->ki_flags & IOCB_DIRECT) {
		if (iocb->ki_flags & IOCB_DIRECT)
			written = ceph_direct_read_write(iocb, &data, snapc,
							 &prealloc_cf);
			ceph_end_io_direct(inode);
		} else {
		else
			written = ceph_sync_write(iocb, &data, pos, snapc);
		if (direct_lock)
			ceph_end_io_direct(inode);
		else
			ceph_end_io_write(inode);
		}
		if (written > 0)
			iov_iter_advance(from, written);
		ceph_put_snap_context(snapc);
@@ -1577,7 +1582,7 @@ retry_snap:

	goto out_unlocked;
out:
	if (iocb->ki_flags & IOCB_DIRECT)
	if (direct_lock)
		ceph_end_io_direct(inode);
	else
		ceph_end_io_write(inode);
+32 −97
Original line number Diff line number Diff line
@@ -202,6 +202,26 @@ struct ceph_parse_opts_ctx {
	struct ceph_mount_options	*opts;
};

/*
 * Remove adjacent slashes and then the trailing slash, unless it is
 * the only remaining character.
 *
 * E.g. "//dir1////dir2///" --> "/dir1/dir2", "///" --> "/".
 */
static void canonicalize_path(char *path)
{
	int i, j = 0;

	for (i = 0; path[i] != '\0'; i++) {
		if (path[i] != '/' || j < 1 || path[j - 1] != '/')
			path[j++] = path[i];
	}

	if (j > 1 && path[j - 1] == '/')
		j--;
	path[j] = '\0';
}

/*
 * Parse the source parameter.  Distinguish the server list from the path.
 *
@@ -224,15 +244,16 @@ static int ceph_parse_source(struct fs_parameter *param, struct fs_context *fc)

	dev_name_end = strchr(dev_name, '/');
	if (dev_name_end) {
		kfree(fsopt->server_path);

		/*
		 * The server_path will include the whole chars from userland
		 * including the leading '/'.
		 */
		kfree(fsopt->server_path);
		fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
		if (!fsopt->server_path)
			return -ENOMEM;

		canonicalize_path(fsopt->server_path);
	} else {
		dev_name_end = dev_name + strlen(dev_name);
	}
@@ -456,73 +477,6 @@ static int strcmp_null(const char *s1, const char *s2)
	return strcmp(s1, s2);
}

/**
 * path_remove_extra_slash - Remove the extra slashes in the server path
 * @server_path: the server path and could be NULL
 *
 * Return NULL if the path is NULL or only consists of "/", or a string
 * without any extra slashes including the leading slash(es) and the
 * slash(es) at the end of the server path, such as:
 * "//dir1////dir2///" --> "dir1/dir2"
 */
static char *path_remove_extra_slash(const char *server_path)
{
	const char *path = server_path;
	const char *cur, *end;
	char *buf, *p;
	int len;

	/* if the server path is omitted */
	if (!path)
		return NULL;

	/* remove all the leading slashes */
	while (*path == '/')
		path++;

	/* if the server path only consists of slashes */
	if (*path == '\0')
		return NULL;

	len = strlen(path);

	buf = kmalloc(len + 1, GFP_KERNEL);
	if (!buf)
		return ERR_PTR(-ENOMEM);

	end = path + len;
	p = buf;
	do {
		cur = strchr(path, '/');
		if (!cur)
			cur = end;

		len = cur - path;

		/* including one '/' */
		if (cur != end)
			len += 1;

		memcpy(p, path, len);
		p += len;

		while (cur <= end && *cur == '/')
			cur++;
		path = cur;
	} while (path < end);

	*p = '\0';

	/*
	 * remove the last slash if there has and just to make sure that
	 * we will get something like "dir1/dir2"
	 */
	if (*(--p) == '/')
		*p = '\0';

	return buf;
}

static int compare_mount_options(struct ceph_mount_options *new_fsopt,
				 struct ceph_options *new_opt,
				 struct ceph_fs_client *fsc)
@@ -530,7 +484,6 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt,
	struct ceph_mount_options *fsopt1 = new_fsopt;
	struct ceph_mount_options *fsopt2 = fsc->mount_options;
	int ofs = offsetof(struct ceph_mount_options, snapdir_name);
	char *p1, *p2;
	int ret;

	ret = memcmp(fsopt1, fsopt2, ofs);
@@ -540,21 +493,12 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt,
	ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name);
	if (ret)
		return ret;

	ret = strcmp_null(fsopt1->mds_namespace, fsopt2->mds_namespace);
	if (ret)
		return ret;

	p1 = path_remove_extra_slash(fsopt1->server_path);
	if (IS_ERR(p1))
		return PTR_ERR(p1);
	p2 = path_remove_extra_slash(fsopt2->server_path);
	if (IS_ERR(p2)) {
		kfree(p1);
		return PTR_ERR(p2);
	}
	ret = strcmp_null(p1, p2);
	kfree(p1);
	kfree(p2);
	ret = strcmp_null(fsopt1->server_path, fsopt2->server_path);
	if (ret)
		return ret;

@@ -957,7 +901,9 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
	mutex_lock(&fsc->client->mount_mutex);

	if (!fsc->sb->s_root) {
		const char *path, *p;
		const char *path = fsc->mount_options->server_path ?
				     fsc->mount_options->server_path + 1 : "";

		err = __ceph_open_session(fsc->client, started);
		if (err < 0)
			goto out;
@@ -969,22 +915,11 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
				goto out;
		}

		p = path_remove_extra_slash(fsc->mount_options->server_path);
		if (IS_ERR(p)) {
			err = PTR_ERR(p);
			goto out;
		}
		/* if the server path is omitted or just consists of '/' */
		if (!p)
			path = "";
		else
			path = p;
		dout("mount opening path '%s'\n", path);

		ceph_fs_debugfs_init(fsc);

		root = open_root_dentry(fsc, path, started);
		kfree(p);
		if (IS_ERR(root)) {
			err = PTR_ERR(root);
			goto out;
@@ -1097,10 +1032,6 @@ static int ceph_get_tree(struct fs_context *fc)
	if (!fc->source)
		return invalfc(fc, "No source");

#ifdef CONFIG_CEPH_FS_POSIX_ACL
	fc->sb_flags |= SB_POSIXACL;
#endif

	/* create client (which we may/may not use) */
	fsc = create_fs_client(pctx->opts, pctx->copts);
	pctx->opts = NULL;
@@ -1223,6 +1154,10 @@ static int ceph_init_fs_context(struct fs_context *fc)
	fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
	fsopt->congestion_kb = default_congestion_kb();

#ifdef CONFIG_CEPH_FS_POSIX_ACL
	fc->sb_flags |= SB_POSIXACL;
#endif

	fc->fs_private = pctx;
	fc->ops = &ceph_context_ops;
	return 0;
+1 −1
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ struct ceph_mount_options {

	char *snapdir_name;   /* default ".snap" */
	char *mds_namespace;  /* default NULL */
	char *server_path;    /* default  "/" */
	char *server_path;    /* default NULL (means "/") */
	char *fscache_uniq;   /* default NULL */
};