mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 00:21:59 +00:00
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:
commit
cf556edfde
@ -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);
|
||||
|
129
fs/ceph/super.c
129
fs/ceph/super.c
@ -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;
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user