Commit cf556edf authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -1418,6 +1418,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -1418,6 +1418,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct ceph_cap_flush *prealloc_cf; struct ceph_cap_flush *prealloc_cf;
ssize_t count, written = 0; ssize_t count, written = 0;
int err, want, got; int err, want, got;
bool direct_lock = false;
loff_t pos; loff_t pos;
loff_t limit = max(i_size_read(inode), fsc->max_file_size); 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) ...@@ -1428,8 +1429,11 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (!prealloc_cf) if (!prealloc_cf)
return -ENOMEM; return -ENOMEM;
if ((iocb->ki_flags & (IOCB_DIRECT | IOCB_APPEND)) == IOCB_DIRECT)
direct_lock = true;
retry_snap: retry_snap:
if (iocb->ki_flags & IOCB_DIRECT) if (direct_lock)
ceph_start_io_direct(inode); ceph_start_io_direct(inode);
else else
ceph_start_io_write(inode); ceph_start_io_write(inode);
...@@ -1519,14 +1523,15 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -1519,14 +1523,15 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
/* we might need to revert back to that point */ /* we might need to revert back to that point */
data = *from; data = *from;
if (iocb->ki_flags & IOCB_DIRECT) { if (iocb->ki_flags & IOCB_DIRECT)
written = ceph_direct_read_write(iocb, &data, snapc, written = ceph_direct_read_write(iocb, &data, snapc,
&prealloc_cf); &prealloc_cf);
ceph_end_io_direct(inode); else
} else {
written = ceph_sync_write(iocb, &data, pos, snapc); written = ceph_sync_write(iocb, &data, pos, snapc);
if (direct_lock)
ceph_end_io_direct(inode);
else
ceph_end_io_write(inode); ceph_end_io_write(inode);
}
if (written > 0) if (written > 0)
iov_iter_advance(from, written); iov_iter_advance(from, written);
ceph_put_snap_context(snapc); ceph_put_snap_context(snapc);
...@@ -1577,7 +1582,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -1577,7 +1582,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
goto out_unlocked; goto out_unlocked;
out: out:
if (iocb->ki_flags & IOCB_DIRECT) if (direct_lock)
ceph_end_io_direct(inode); ceph_end_io_direct(inode);
else else
ceph_end_io_write(inode); ceph_end_io_write(inode);
......
...@@ -202,6 +202,26 @@ struct ceph_parse_opts_ctx { ...@@ -202,6 +202,26 @@ struct ceph_parse_opts_ctx {
struct ceph_mount_options *opts; 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. * 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) ...@@ -224,15 +244,16 @@ static int ceph_parse_source(struct fs_parameter *param, struct fs_context *fc)
dev_name_end = strchr(dev_name, '/'); dev_name_end = strchr(dev_name, '/');
if (dev_name_end) { if (dev_name_end) {
kfree(fsopt->server_path);
/* /*
* The server_path will include the whole chars from userland * The server_path will include the whole chars from userland
* including the leading '/'. * including the leading '/'.
*/ */
kfree(fsopt->server_path);
fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL); fsopt->server_path = kstrdup(dev_name_end, GFP_KERNEL);
if (!fsopt->server_path) if (!fsopt->server_path)
return -ENOMEM; return -ENOMEM;
canonicalize_path(fsopt->server_path);
} else { } else {
dev_name_end = dev_name + strlen(dev_name); dev_name_end = dev_name + strlen(dev_name);
} }
...@@ -456,73 +477,6 @@ static int strcmp_null(const char *s1, const char *s2) ...@@ -456,73 +477,6 @@ static int strcmp_null(const char *s1, const char *s2)
return strcmp(s1, 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, static int compare_mount_options(struct ceph_mount_options *new_fsopt,
struct ceph_options *new_opt, struct ceph_options *new_opt,
struct ceph_fs_client *fsc) struct ceph_fs_client *fsc)
...@@ -530,7 +484,6 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt, ...@@ -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 *fsopt1 = new_fsopt;
struct ceph_mount_options *fsopt2 = fsc->mount_options; struct ceph_mount_options *fsopt2 = fsc->mount_options;
int ofs = offsetof(struct ceph_mount_options, snapdir_name); int ofs = offsetof(struct ceph_mount_options, snapdir_name);
char *p1, *p2;
int ret; int ret;
ret = memcmp(fsopt1, fsopt2, ofs); ret = memcmp(fsopt1, fsopt2, ofs);
...@@ -540,21 +493,12 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt, ...@@ -540,21 +493,12 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt,
ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name); ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name);
if (ret) if (ret)
return ret; return ret;
ret = strcmp_null(fsopt1->mds_namespace, fsopt2->mds_namespace); ret = strcmp_null(fsopt1->mds_namespace, fsopt2->mds_namespace);
if (ret) if (ret)
return ret; return ret;
p1 = path_remove_extra_slash(fsopt1->server_path); ret = strcmp_null(fsopt1->server_path, fsopt2->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);
if (ret) if (ret)
return ret; return ret;
...@@ -957,7 +901,9 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc, ...@@ -957,7 +901,9 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
mutex_lock(&fsc->client->mount_mutex); mutex_lock(&fsc->client->mount_mutex);
if (!fsc->sb->s_root) { 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); err = __ceph_open_session(fsc->client, started);
if (err < 0) if (err < 0)
goto out; goto out;
...@@ -969,22 +915,11 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc, ...@@ -969,22 +915,11 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
goto out; 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); dout("mount opening path '%s'\n", path);
ceph_fs_debugfs_init(fsc); ceph_fs_debugfs_init(fsc);
root = open_root_dentry(fsc, path, started); root = open_root_dentry(fsc, path, started);
kfree(p);
if (IS_ERR(root)) { if (IS_ERR(root)) {
err = PTR_ERR(root); err = PTR_ERR(root);
goto out; goto out;
...@@ -1097,10 +1032,6 @@ static int ceph_get_tree(struct fs_context *fc) ...@@ -1097,10 +1032,6 @@ static int ceph_get_tree(struct fs_context *fc)
if (!fc->source) if (!fc->source)
return invalfc(fc, "No 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) */ /* create client (which we may/may not use) */
fsc = create_fs_client(pctx->opts, pctx->copts); fsc = create_fs_client(pctx->opts, pctx->copts);
pctx->opts = NULL; pctx->opts = NULL;
...@@ -1223,6 +1154,10 @@ static int ceph_init_fs_context(struct fs_context *fc) ...@@ -1223,6 +1154,10 @@ static int ceph_init_fs_context(struct fs_context *fc)
fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT; fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
fsopt->congestion_kb = default_congestion_kb(); fsopt->congestion_kb = default_congestion_kb();
#ifdef CONFIG_CEPH_FS_POSIX_ACL
fc->sb_flags |= SB_POSIXACL;
#endif
fc->fs_private = pctx; fc->fs_private = pctx;
fc->ops = &ceph_context_ops; fc->ops = &ceph_context_ops;
return 0; return 0;
......
...@@ -91,7 +91,7 @@ struct ceph_mount_options { ...@@ -91,7 +91,7 @@ struct ceph_mount_options {
char *snapdir_name; /* default ".snap" */ char *snapdir_name; /* default ".snap" */
char *mds_namespace; /* default NULL */ char *mds_namespace; /* default NULL */
char *server_path; /* default "/" */ char *server_path; /* default NULL (means "/") */
char *fscache_uniq; /* default NULL */ char *fscache_uniq; /* default NULL */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment