A patch to make O_DIRECT | O_APPEND combination work better, a redo

of server path canonicalization patch that went into -rc1 and a fixup
 for noacl mount option that got broken by the conversion to the new
 mount API in 5.5.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCAAxFiEEydHwtzie9C7TfviiSn/eOAIR84sFAl5GzToTHGlkcnlvbW92
 QGdtYWlsLmNvbQAKCRBKf944AhHzi6tKB/9VZ5DIkd5m3UyKh+rgw565LddPiJTU
 zIngCUV2EwyRyTwgOCMzG/AsCxcjQDS3RzEZsCCIpAsT09vAJxP0uFFm8o3LE0xX
 NX8F/0cHc14lqpI39dzB3HiBETx3XIf3eNUpSJphtwKqmn3MOhAASPK9xDZdICNh
 VziVMOogns4QEYTxY+aA5DoKmkOuuolCVKUZj7/fyFXX90NGhLVBsIfRIuIE2O0v
 xbtitsGqqZtf+1Iar4gKRLIWCpwzETSBE9G+GJlxqUSDz2VTovDDhn6tBtu65m8d
 APvN9+Le355ts9iFuep3SYkYQhNXRZ/ydxx3fOqTM60Tzi3cVTtO+Mk4
 =YoNz
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2020-02-14 14:42:31 -08:00
commit cf556edfde
3 changed files with 44 additions and 104 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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 */
};