Commit 556e2d17 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ceph-for-6.8-rc1' of https://github.com/ceph/ceph-client

Pull ceph updates from Ilya Dryomov:
 "Assorted CephFS fixes and cleanups with nothing standing out"

* tag 'ceph-for-6.8-rc1' of https://github.com/ceph/ceph-client:
  ceph: get rid of passing callbacks in __dentry_leases_walk()
  ceph: d_obtain_{alias,root}(ERR_PTR(...)) will do the right thing
  ceph: fix invalid pointer access if get_quota_realm return ERR_PTR
  ceph: remove duplicated code in ceph_netfs_issue_read()
  ceph: send oldest_client_tid when renewing caps
  ceph: rename create_session_open_msg() to create_session_full_msg()
  ceph: select FS_ENCRYPTION_ALGS if FS_ENCRYPTION
  ceph: fix deadlock or deadcode of misusing dget()
  ceph: try to allocate a smaller extent map for sparse read
  libceph: remove MAX_EXTENTS check for sparse reads
  ceph: reinitialize mds feature bit even when session in open
  ceph: skip reconnecting if MDS is not ready
parents ec2d264a 2a965d1b
...@@ -7,6 +7,7 @@ config CEPH_FS ...@@ -7,6 +7,7 @@ config CEPH_FS
select CRYPTO_AES select CRYPTO_AES
select CRYPTO select CRYPTO
select NETFS_SUPPORT select NETFS_SUPPORT
select FS_ENCRYPTION_ALGS if FS_ENCRYPTION
default n default n
help help
Choose Y or M here to include support for mounting the Choose Y or M here to include support for mounting the
......
...@@ -337,6 +337,7 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq) ...@@ -337,6 +337,7 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
u64 len = subreq->len; u64 len = subreq->len;
bool sparse = IS_ENCRYPTED(inode) || ceph_test_mount_opt(fsc, SPARSEREAD); bool sparse = IS_ENCRYPTED(inode) || ceph_test_mount_opt(fsc, SPARSEREAD);
u64 off = subreq->start; u64 off = subreq->start;
int extent_cnt;
if (ceph_inode_is_shutdown(inode)) { if (ceph_inode_is_shutdown(inode)) {
err = -EIO; err = -EIO;
...@@ -350,8 +351,8 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq) ...@@ -350,8 +351,8 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, vino, req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, vino,
off, &len, 0, 1, sparse ? CEPH_OSD_OP_SPARSE_READ : CEPH_OSD_OP_READ, off, &len, 0, 1, sparse ? CEPH_OSD_OP_SPARSE_READ : CEPH_OSD_OP_READ,
CEPH_OSD_FLAG_READ | fsc->client->osdc.client->options->read_from_replica, CEPH_OSD_FLAG_READ, NULL, ci->i_truncate_seq,
NULL, ci->i_truncate_seq, ci->i_truncate_size, false); ci->i_truncate_size, false);
if (IS_ERR(req)) { if (IS_ERR(req)) {
err = PTR_ERR(req); err = PTR_ERR(req);
req = NULL; req = NULL;
...@@ -359,7 +360,8 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq) ...@@ -359,7 +360,8 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
} }
if (sparse) { if (sparse) {
err = ceph_alloc_sparse_ext_map(&req->r_ops[0]); extent_cnt = __ceph_sparse_read_ext_count(inode, len);
err = ceph_alloc_sparse_ext_map(&req->r_ops[0], extent_cnt);
if (err) if (err)
goto out; goto out;
} }
......
...@@ -4887,13 +4887,15 @@ int ceph_encode_dentry_release(void **p, struct dentry *dentry, ...@@ -4887,13 +4887,15 @@ int ceph_encode_dentry_release(void **p, struct dentry *dentry,
struct inode *dir, struct inode *dir,
int mds, int drop, int unless) int mds, int drop, int unless)
{ {
struct dentry *parent = NULL;
struct ceph_mds_request_release *rel = *p; struct ceph_mds_request_release *rel = *p;
struct ceph_dentry_info *di = ceph_dentry(dentry); struct ceph_dentry_info *di = ceph_dentry(dentry);
struct ceph_client *cl; struct ceph_client *cl;
int force = 0; int force = 0;
int ret; int ret;
/* This shouldn't happen */
BUG_ON(!dir);
/* /*
* force an record for the directory caps if we have a dentry lease. * force an record for the directory caps if we have a dentry lease.
* this is racy (can't take i_ceph_lock and d_lock together), but it * this is racy (can't take i_ceph_lock and d_lock together), but it
...@@ -4903,14 +4905,9 @@ int ceph_encode_dentry_release(void **p, struct dentry *dentry, ...@@ -4903,14 +4905,9 @@ int ceph_encode_dentry_release(void **p, struct dentry *dentry,
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
if (di->lease_session && di->lease_session->s_mds == mds) if (di->lease_session && di->lease_session->s_mds == mds)
force = 1; force = 1;
if (!dir) {
parent = dget(dentry->d_parent);
dir = d_inode(parent);
}
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
ret = ceph_encode_inode_release(p, dir, mds, drop, unless, force); ret = ceph_encode_inode_release(p, dir, mds, drop, unless, force);
dput(parent);
cl = ceph_inode_to_client(dir); cl = ceph_inode_to_client(dir);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
......
...@@ -1593,10 +1593,12 @@ struct ceph_lease_walk_control { ...@@ -1593,10 +1593,12 @@ struct ceph_lease_walk_control {
unsigned long dir_lease_ttl; unsigned long dir_lease_ttl;
}; };
static int __dir_lease_check(const struct dentry *, struct ceph_lease_walk_control *);
static int __dentry_lease_check(const struct dentry *);
static unsigned long static unsigned long
__dentry_leases_walk(struct ceph_mds_client *mdsc, __dentry_leases_walk(struct ceph_mds_client *mdsc,
struct ceph_lease_walk_control *lwc, struct ceph_lease_walk_control *lwc)
int (*check)(struct dentry*, void*))
{ {
struct ceph_dentry_info *di, *tmp; struct ceph_dentry_info *di, *tmp;
struct dentry *dentry, *last = NULL; struct dentry *dentry, *last = NULL;
...@@ -1624,7 +1626,10 @@ __dentry_leases_walk(struct ceph_mds_client *mdsc, ...@@ -1624,7 +1626,10 @@ __dentry_leases_walk(struct ceph_mds_client *mdsc,
goto next; goto next;
} }
ret = check(dentry, lwc); if (lwc->dir_lease)
ret = __dir_lease_check(dentry, lwc);
else
ret = __dentry_lease_check(dentry);
if (ret & TOUCH) { if (ret & TOUCH) {
/* move it into tail of dir lease list */ /* move it into tail of dir lease list */
__dentry_dir_lease_touch(mdsc, di); __dentry_dir_lease_touch(mdsc, di);
...@@ -1681,7 +1686,7 @@ __dentry_leases_walk(struct ceph_mds_client *mdsc, ...@@ -1681,7 +1686,7 @@ __dentry_leases_walk(struct ceph_mds_client *mdsc,
return freed; return freed;
} }
static int __dentry_lease_check(struct dentry *dentry, void *arg) static int __dentry_lease_check(const struct dentry *dentry)
{ {
struct ceph_dentry_info *di = ceph_dentry(dentry); struct ceph_dentry_info *di = ceph_dentry(dentry);
int ret; int ret;
...@@ -1696,9 +1701,9 @@ static int __dentry_lease_check(struct dentry *dentry, void *arg) ...@@ -1696,9 +1701,9 @@ static int __dentry_lease_check(struct dentry *dentry, void *arg)
return DELETE; return DELETE;
} }
static int __dir_lease_check(struct dentry *dentry, void *arg) static int __dir_lease_check(const struct dentry *dentry,
struct ceph_lease_walk_control *lwc)
{ {
struct ceph_lease_walk_control *lwc = arg;
struct ceph_dentry_info *di = ceph_dentry(dentry); struct ceph_dentry_info *di = ceph_dentry(dentry);
int ret = __dir_lease_try_check(dentry); int ret = __dir_lease_try_check(dentry);
...@@ -1737,7 +1742,7 @@ int ceph_trim_dentries(struct ceph_mds_client *mdsc) ...@@ -1737,7 +1742,7 @@ int ceph_trim_dentries(struct ceph_mds_client *mdsc)
lwc.dir_lease = false; lwc.dir_lease = false;
lwc.nr_to_scan = CEPH_CAPS_PER_RELEASE * 2; lwc.nr_to_scan = CEPH_CAPS_PER_RELEASE * 2;
freed = __dentry_leases_walk(mdsc, &lwc, __dentry_lease_check); freed = __dentry_leases_walk(mdsc, &lwc);
if (!lwc.nr_to_scan) /* more invalid leases */ if (!lwc.nr_to_scan) /* more invalid leases */
return -EAGAIN; return -EAGAIN;
...@@ -1747,7 +1752,7 @@ int ceph_trim_dentries(struct ceph_mds_client *mdsc) ...@@ -1747,7 +1752,7 @@ int ceph_trim_dentries(struct ceph_mds_client *mdsc)
lwc.dir_lease = true; lwc.dir_lease = true;
lwc.expire_dir_lease = freed < count; lwc.expire_dir_lease = freed < count;
lwc.dir_lease_ttl = mdsc->fsc->mount_options->caps_wanted_delay_max * HZ; lwc.dir_lease_ttl = mdsc->fsc->mount_options->caps_wanted_delay_max * HZ;
freed +=__dentry_leases_walk(mdsc, &lwc, __dir_lease_check); freed +=__dentry_leases_walk(mdsc, &lwc);
if (!lwc.nr_to_scan) /* more to check */ if (!lwc.nr_to_scan) /* more to check */
return -EAGAIN; return -EAGAIN;
......
...@@ -286,8 +286,6 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb, ...@@ -286,8 +286,6 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb,
doutc(cl, "%llx.%llx parent %llx hash %x err=%d", vino.ino, doutc(cl, "%llx.%llx parent %llx hash %x err=%d", vino.ino,
vino.snap, sfh->parent_ino, sfh->hash, err); vino.snap, sfh->parent_ino, sfh->hash, err);
} }
if (IS_ERR(inode))
return ERR_CAST(inode);
/* see comments in ceph_get_parent() */ /* see comments in ceph_get_parent() */
return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode); return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode);
} }
......
...@@ -1029,6 +1029,7 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos, ...@@ -1029,6 +1029,7 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
struct ceph_osd_req_op *op; struct ceph_osd_req_op *op;
u64 read_off = off; u64 read_off = off;
u64 read_len = len; u64 read_len = len;
int extent_cnt;
/* determine new offset/length if encrypted */ /* determine new offset/length if encrypted */
ceph_fscrypt_adjust_off_and_len(inode, &read_off, &read_len); ceph_fscrypt_adjust_off_and_len(inode, &read_off, &read_len);
...@@ -1068,7 +1069,8 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos, ...@@ -1068,7 +1069,8 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
op = &req->r_ops[0]; op = &req->r_ops[0];
if (sparse) { if (sparse) {
ret = ceph_alloc_sparse_ext_map(op); extent_cnt = __ceph_sparse_read_ext_count(inode, read_len);
ret = ceph_alloc_sparse_ext_map(op, extent_cnt);
if (ret) { if (ret) {
ceph_osdc_put_request(req); ceph_osdc_put_request(req);
break; break;
...@@ -1465,6 +1467,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, ...@@ -1465,6 +1467,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
ssize_t len; ssize_t len;
struct ceph_osd_req_op *op; struct ceph_osd_req_op *op;
int readop = sparse ? CEPH_OSD_OP_SPARSE_READ : CEPH_OSD_OP_READ; int readop = sparse ? CEPH_OSD_OP_SPARSE_READ : CEPH_OSD_OP_READ;
int extent_cnt;
if (write) if (write)
size = min_t(u64, size, fsc->mount_options->wsize); size = min_t(u64, size, fsc->mount_options->wsize);
...@@ -1528,7 +1531,8 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, ...@@ -1528,7 +1531,8 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
osd_req_op_extent_osd_data_bvecs(req, 0, bvecs, num_pages, len); osd_req_op_extent_osd_data_bvecs(req, 0, bvecs, num_pages, len);
op = &req->r_ops[0]; op = &req->r_ops[0];
if (sparse) { if (sparse) {
ret = ceph_alloc_sparse_ext_map(op); extent_cnt = __ceph_sparse_read_ext_count(inode, size);
ret = ceph_alloc_sparse_ext_map(op, extent_cnt);
if (ret) { if (ret) {
ceph_osdc_put_request(req); ceph_osdc_put_request(req);
break; break;
......
...@@ -1534,7 +1534,8 @@ static int encode_metric_spec(void **p, void *end) ...@@ -1534,7 +1534,8 @@ static int encode_metric_spec(void **p, void *end)
* session message, specialization for CEPH_SESSION_REQUEST_OPEN * session message, specialization for CEPH_SESSION_REQUEST_OPEN
* to include additional client metadata fields. * to include additional client metadata fields.
*/ */
static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u64 seq) static struct ceph_msg *
create_session_full_msg(struct ceph_mds_client *mdsc, int op, u64 seq)
{ {
struct ceph_msg *msg; struct ceph_msg *msg;
struct ceph_mds_session_head *h; struct ceph_mds_session_head *h;
...@@ -1578,6 +1579,9 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6 ...@@ -1578,6 +1579,9 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6
size = METRIC_BYTES(count); size = METRIC_BYTES(count);
extra_bytes += 2 + 4 + 4 + size; extra_bytes += 2 + 4 + 4 + size;
/* flags, mds auth caps and oldest_client_tid */
extra_bytes += 4 + 4 + 8;
/* Allocate the message */ /* Allocate the message */
msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h) + extra_bytes, msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h) + extra_bytes,
GFP_NOFS, false); GFP_NOFS, false);
...@@ -1589,16 +1593,16 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6 ...@@ -1589,16 +1593,16 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6
end = p + msg->front.iov_len; end = p + msg->front.iov_len;
h = p; h = p;
h->op = cpu_to_le32(CEPH_SESSION_REQUEST_OPEN); h->op = cpu_to_le32(op);
h->seq = cpu_to_le64(seq); h->seq = cpu_to_le64(seq);
/* /*
* Serialize client metadata into waiting buffer space, using * Serialize client metadata into waiting buffer space, using
* the format that userspace expects for map<string, string> * the format that userspace expects for map<string, string>
* *
* ClientSession messages with metadata are v4 * ClientSession messages with metadata are v7
*/ */
msg->hdr.version = cpu_to_le16(4); msg->hdr.version = cpu_to_le16(7);
msg->hdr.compat_version = cpu_to_le16(1); msg->hdr.compat_version = cpu_to_le16(1);
/* The write pointer, following the session_head structure */ /* The write pointer, following the session_head structure */
...@@ -1634,6 +1638,15 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6 ...@@ -1634,6 +1638,15 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6
return ERR_PTR(ret); return ERR_PTR(ret);
} }
/* version == 5, flags */
ceph_encode_32(&p, 0);
/* version == 6, mds auth caps */
ceph_encode_32(&p, 0);
/* version == 7, oldest_client_tid */
ceph_encode_64(&p, mdsc->oldest_tid);
msg->front.iov_len = p - msg->front.iov_base; msg->front.iov_len = p - msg->front.iov_base;
msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
...@@ -1663,7 +1676,8 @@ static int __open_session(struct ceph_mds_client *mdsc, ...@@ -1663,7 +1676,8 @@ static int __open_session(struct ceph_mds_client *mdsc,
session->s_renew_requested = jiffies; session->s_renew_requested = jiffies;
/* send connect message */ /* send connect message */
msg = create_session_open_msg(mdsc, session->s_seq); msg = create_session_full_msg(mdsc, CEPH_SESSION_REQUEST_OPEN,
session->s_seq);
if (IS_ERR(msg)) if (IS_ERR(msg))
return PTR_ERR(msg); return PTR_ERR(msg);
ceph_con_send(&session->s_con, msg); ceph_con_send(&session->s_con, msg);
...@@ -2028,10 +2042,10 @@ static int send_renew_caps(struct ceph_mds_client *mdsc, ...@@ -2028,10 +2042,10 @@ static int send_renew_caps(struct ceph_mds_client *mdsc,
doutc(cl, "to mds%d (%s)\n", session->s_mds, doutc(cl, "to mds%d (%s)\n", session->s_mds,
ceph_mds_state_name(state)); ceph_mds_state_name(state));
msg = ceph_create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS, msg = create_session_full_msg(mdsc, CEPH_SESSION_REQUEST_RENEWCAPS,
++session->s_renew_seq); ++session->s_renew_seq);
if (!msg) if (IS_ERR(msg))
return -ENOMEM; return PTR_ERR(msg);
ceph_con_send(&session->s_con, msg); ceph_con_send(&session->s_con, msg);
return 0; return 0;
} }
...@@ -4128,12 +4142,12 @@ static void handle_session(struct ceph_mds_session *session, ...@@ -4128,12 +4142,12 @@ static void handle_session(struct ceph_mds_session *session,
pr_info_client(cl, "mds%d reconnect success\n", pr_info_client(cl, "mds%d reconnect success\n",
session->s_mds); session->s_mds);
session->s_features = features;
if (session->s_state == CEPH_MDS_SESSION_OPEN) { if (session->s_state == CEPH_MDS_SESSION_OPEN) {
pr_notice_client(cl, "mds%d is already opened\n", pr_notice_client(cl, "mds%d is already opened\n",
session->s_mds); session->s_mds);
} else { } else {
session->s_state = CEPH_MDS_SESSION_OPEN; session->s_state = CEPH_MDS_SESSION_OPEN;
session->s_features = features;
renewed_caps(mdsc, session, 0); renewed_caps(mdsc, session, 0);
if (test_bit(CEPHFS_FEATURE_METRIC_COLLECT, if (test_bit(CEPHFS_FEATURE_METRIC_COLLECT,
&session->s_features)) &session->s_features))
...@@ -5870,7 +5884,8 @@ static void mds_peer_reset(struct ceph_connection *con) ...@@ -5870,7 +5884,8 @@ static void mds_peer_reset(struct ceph_connection *con)
pr_warn_client(mdsc->fsc->client, "mds%d closed our session\n", pr_warn_client(mdsc->fsc->client, "mds%d closed our session\n",
s->s_mds); s->s_mds);
if (READ_ONCE(mdsc->fsc->mount_state) != CEPH_MOUNT_FENCE_IO) if (READ_ONCE(mdsc->fsc->mount_state) != CEPH_MOUNT_FENCE_IO &&
ceph_mdsmap_get_state(mdsc->mdsmap, s->s_mds) >= CEPH_MDS_STATE_RECONNECT)
send_mds_reconnect(mdsc, s); send_mds_reconnect(mdsc, s);
} }
......
...@@ -197,10 +197,10 @@ void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc) ...@@ -197,10 +197,10 @@ void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc)
} }
/* /*
* This function walks through the snaprealm for an inode and returns the * This function walks through the snaprealm for an inode and set the
* ceph_snap_realm for the first snaprealm that has quotas set (max_files, * realmp with the first snaprealm that has quotas set (max_files,
* max_bytes, or any, depending on the 'which_quota' argument). If the root is * max_bytes, or any, depending on the 'which_quota' argument). If the root is
* reached, return the root ceph_snap_realm instead. * reached, set the realmp with the root ceph_snap_realm instead.
* *
* Note that the caller is responsible for calling ceph_put_snap_realm() on the * Note that the caller is responsible for calling ceph_put_snap_realm() on the
* returned realm. * returned realm.
...@@ -211,10 +211,9 @@ void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc) ...@@ -211,10 +211,9 @@ void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc)
* this function will return -EAGAIN; otherwise, the snaprealms walk-through * this function will return -EAGAIN; otherwise, the snaprealms walk-through
* will be restarted. * will be restarted.
*/ */
static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, static int get_quota_realm(struct ceph_mds_client *mdsc, struct inode *inode,
struct inode *inode,
enum quota_get_realm which_quota, enum quota_get_realm which_quota,
bool retry) struct ceph_snap_realm **realmp, bool retry)
{ {
struct ceph_client *cl = mdsc->fsc->client; struct ceph_client *cl = mdsc->fsc->client;
struct ceph_inode_info *ci = NULL; struct ceph_inode_info *ci = NULL;
...@@ -222,8 +221,10 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, ...@@ -222,8 +221,10 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
struct inode *in; struct inode *in;
bool has_quota; bool has_quota;
if (realmp)
*realmp = NULL;
if (ceph_snap(inode) != CEPH_NOSNAP) if (ceph_snap(inode) != CEPH_NOSNAP)
return NULL; return 0;
restart: restart:
realm = ceph_inode(inode)->i_snap_realm; realm = ceph_inode(inode)->i_snap_realm;
...@@ -250,7 +251,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, ...@@ -250,7 +251,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
break; break;
ceph_put_snap_realm(mdsc, realm); ceph_put_snap_realm(mdsc, realm);
if (!retry) if (!retry)
return ERR_PTR(-EAGAIN); return -EAGAIN;
goto restart; goto restart;
} }
...@@ -259,8 +260,11 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, ...@@ -259,8 +260,11 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
iput(in); iput(in);
next = realm->parent; next = realm->parent;
if (has_quota || !next) if (has_quota || !next) {
return realm; if (realmp)
*realmp = realm;
return 0;
}
ceph_get_snap_realm(mdsc, next); ceph_get_snap_realm(mdsc, next);
ceph_put_snap_realm(mdsc, realm); ceph_put_snap_realm(mdsc, realm);
...@@ -269,7 +273,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc, ...@@ -269,7 +273,7 @@ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
if (realm) if (realm)
ceph_put_snap_realm(mdsc, realm); ceph_put_snap_realm(mdsc, realm);
return NULL; return 0;
} }
bool ceph_quota_is_same_realm(struct inode *old, struct inode *new) bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
...@@ -277,6 +281,7 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new) ...@@ -277,6 +281,7 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(old->i_sb); struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(old->i_sb);
struct ceph_snap_realm *old_realm, *new_realm; struct ceph_snap_realm *old_realm, *new_realm;
bool is_same; bool is_same;
int ret;
restart: restart:
/* /*
...@@ -286,9 +291,9 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new) ...@@ -286,9 +291,9 @@ bool ceph_quota_is_same_realm(struct inode *old, struct inode *new)
* dropped and we can then restart the whole operation. * dropped and we can then restart the whole operation.
*/ */
down_read(&mdsc->snap_rwsem); down_read(&mdsc->snap_rwsem);
old_realm = get_quota_realm(mdsc, old, QUOTA_GET_ANY, true); get_quota_realm(mdsc, old, QUOTA_GET_ANY, &old_realm, true);
new_realm = get_quota_realm(mdsc, new, QUOTA_GET_ANY, false); ret = get_quota_realm(mdsc, new, QUOTA_GET_ANY, &new_realm, false);
if (PTR_ERR(new_realm) == -EAGAIN) { if (ret == -EAGAIN) {
up_read(&mdsc->snap_rwsem); up_read(&mdsc->snap_rwsem);
if (old_realm) if (old_realm)
ceph_put_snap_realm(mdsc, old_realm); ceph_put_snap_realm(mdsc, old_realm);
...@@ -492,8 +497,8 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf) ...@@ -492,8 +497,8 @@ bool ceph_quota_update_statfs(struct ceph_fs_client *fsc, struct kstatfs *buf)
bool is_updated = false; bool is_updated = false;
down_read(&mdsc->snap_rwsem); down_read(&mdsc->snap_rwsem);
realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root), get_quota_realm(mdsc, d_inode(fsc->sb->s_root), QUOTA_GET_MAX_BYTES,
QUOTA_GET_MAX_BYTES, true); &realm, true);
up_read(&mdsc->snap_rwsem); up_read(&mdsc->snap_rwsem);
if (!realm) if (!realm)
return false; return false;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#define _FS_CEPH_SUPER_H #define _FS_CEPH_SUPER_H
#include <linux/ceph/ceph_debug.h> #include <linux/ceph/ceph_debug.h>
#include <linux/ceph/osd_client.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
...@@ -1407,6 +1408,19 @@ static inline void __ceph_update_quota(struct ceph_inode_info *ci, ...@@ -1407,6 +1408,19 @@ static inline void __ceph_update_quota(struct ceph_inode_info *ci,
ceph_adjust_quota_realms_count(&ci->netfs.inode, has_quota); ceph_adjust_quota_realms_count(&ci->netfs.inode, has_quota);
} }
static inline int __ceph_sparse_read_ext_count(struct inode *inode, u64 len)
{
int cnt = 0;
if (IS_ENCRYPTED(inode)) {
cnt = len >> CEPH_FSCRYPT_BLOCK_SHIFT;
if (cnt > CEPH_SPARSE_EXT_ARRAY_INITIAL)
cnt = 0;
}
return cnt;
}
extern void ceph_handle_quota(struct ceph_mds_client *mdsc, extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
struct ceph_mds_session *session, struct ceph_mds_session *session,
struct ceph_msg *msg); struct ceph_msg *msg);
......
...@@ -572,9 +572,12 @@ int __ceph_alloc_sparse_ext_map(struct ceph_osd_req_op *op, int cnt); ...@@ -572,9 +572,12 @@ int __ceph_alloc_sparse_ext_map(struct ceph_osd_req_op *op, int cnt);
*/ */
#define CEPH_SPARSE_EXT_ARRAY_INITIAL 16 #define CEPH_SPARSE_EXT_ARRAY_INITIAL 16
static inline int ceph_alloc_sparse_ext_map(struct ceph_osd_req_op *op) static inline int ceph_alloc_sparse_ext_map(struct ceph_osd_req_op *op, int cnt)
{ {
return __ceph_alloc_sparse_ext_map(op, CEPH_SPARSE_EXT_ARRAY_INITIAL); if (!cnt)
cnt = CEPH_SPARSE_EXT_ARRAY_INITIAL;
return __ceph_alloc_sparse_ext_map(op, cnt);
} }
extern void ceph_osdc_get_request(struct ceph_osd_request *req); extern void ceph_osdc_get_request(struct ceph_osd_request *req);
......
...@@ -5850,8 +5850,6 @@ static inline void convert_extent_map(struct ceph_sparse_read *sr) ...@@ -5850,8 +5850,6 @@ static inline void convert_extent_map(struct ceph_sparse_read *sr)
} }
#endif #endif
#define MAX_EXTENTS 4096
static int osd_sparse_read(struct ceph_connection *con, static int osd_sparse_read(struct ceph_connection *con,
struct ceph_msg_data_cursor *cursor, struct ceph_msg_data_cursor *cursor,
char **pbuf) char **pbuf)
...@@ -5882,23 +5880,16 @@ static int osd_sparse_read(struct ceph_connection *con, ...@@ -5882,23 +5880,16 @@ static int osd_sparse_read(struct ceph_connection *con,
if (count > 0) { if (count > 0) {
if (!sr->sr_extent || count > sr->sr_ext_len) { if (!sr->sr_extent || count > sr->sr_ext_len) {
/*
* Apply a hard cap to the number of extents.
* If we have more, assume something is wrong.
*/
if (count > MAX_EXTENTS) {
dout("%s: OSD returned 0x%x extents in a single reply!\n",
__func__, count);
return -EREMOTEIO;
}
/* no extent array provided, or too short */ /* no extent array provided, or too short */
kfree(sr->sr_extent); kfree(sr->sr_extent);
sr->sr_extent = kmalloc_array(count, sr->sr_extent = kmalloc_array(count,
sizeof(*sr->sr_extent), sizeof(*sr->sr_extent),
GFP_NOIO); GFP_NOIO);
if (!sr->sr_extent) if (!sr->sr_extent) {
pr_err("%s: failed to allocate %u extents\n",
__func__, count);
return -ENOMEM; return -ENOMEM;
}
sr->sr_ext_len = count; sr->sr_ext_len = count;
} }
ret = count * sizeof(*sr->sr_extent); ret = count * sizeof(*sr->sr_extent);
......
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