Home Home > GIT Browse > SLE15-SP1-AZURE
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Tesarik <ptesarik@suse.cz>2019-06-21 21:05:39 +0200
committerPetr Tesarik <ptesarik@suse.cz>2019-06-21 21:05:39 +0200
commitbb88551acfe873fcbfd967954276a906293df0f9 (patch)
tree9124125f248f7020b46a7d5737ca971cf46627a6
parent39708dc5de7505e844b8e0a8265c582dbc65c428 (diff)
parentd183b277f9338daa57d2b93a6fe2a2522fae768d (diff)
Merge branch 'users/lhenriques/SLE15-SP1/for-next' into SLE15-SP1
Pull ceph fixes from Luis Henriques
-rw-r--r--patches.fixes/ceph-factor-out-ceph_lookup_inode.patch64
-rw-r--r--patches.fixes/ceph-fix-null-pointer-deref-when-debugging-is-enabled.patch25
-rw-r--r--patches.fixes/ceph-fix-potential-use-after-free-in-ceph_mdsc_build_path.patch57
-rw-r--r--patches.fixes/ceph-flush-dirty-inodes-before-proceeding-with-remount.patch48
-rw-r--r--patches.fixes/ceph-print-inode-number-in-_caps_issued_mask-debugging-messages.patch55
-rw-r--r--patches.fixes/ceph-quota-fix-quota-subdir-mounts.patch347
-rw-r--r--patches.fixes/ceph-remove-duplicated-filelock-ref-increase.patch53
-rw-r--r--patches.fixes/rbd-don-t-assert-on-writes-to-snapshots.patch44
-rw-r--r--series.conf8
9 files changed, 701 insertions, 0 deletions
diff --git a/patches.fixes/ceph-factor-out-ceph_lookup_inode.patch b/patches.fixes/ceph-factor-out-ceph_lookup_inode.patch
new file mode 100644
index 0000000000..54ce69dae3
--- /dev/null
+++ b/patches.fixes/ceph-factor-out-ceph_lookup_inode.patch
@@ -0,0 +1,64 @@
+From: Luis Henriques <lhenriques@suse.com>
+Date: Thu, 21 Mar 2019 10:20:09 +0000
+Subject: ceph: factor out ceph_lookup_inode()
+Git-commit: 3886274adf34a4e38417772e3d1c0b213380004e
+Patch-mainline: v5.2-rc1
+References: bsc#1138681
+
+This function will be used by __fh_to_dentry and by the quotas code, to
+find quota realm inodes that are not visible in the mountpoint.
+
+Signed-off-by: Luis Henriques <lhenriques@suse.com>
+Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+---
+ fs/ceph/export.c | 14 ++++++++++++--
+ fs/ceph/super.h | 1 +
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/fs/ceph/export.c
++++ b/fs/ceph/export.c
+@@ -58,7 +58,7 @@ static int ceph_encode_fh(struct inode *
+ return type;
+ }
+
+-static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
++struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino)
+ {
+ struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
+ struct inode *inode;
+@@ -90,13 +90,23 @@ static struct dentry *__fh_to_dentry(str
+ ihold(inode);
+ ceph_mdsc_put_request(req);
+ if (!inode)
+- return ERR_PTR(-ESTALE);
++ return err < 0 ? ERR_PTR(err) : ERR_PTR(-ESTALE);
+ if (inode->i_nlink == 0) {
+ iput(inode);
+ return ERR_PTR(-ESTALE);
+ }
+ }
+
++ return inode;
++}
++
++static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
++{
++ struct inode *inode = ceph_lookup_inode(sb, ino);
++
++ if (IS_ERR(inode))
++ return ERR_CAST(inode);
++
+ return d_obtain_alias(inode);
+ }
+
+--- a/fs/ceph/super.h
++++ b/fs/ceph/super.h
+@@ -1057,6 +1057,7 @@ extern long ceph_ioctl(struct file *file
+
+ /* export.c */
+ extern const struct export_operations ceph_export_ops;
++struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino);
+
+ /* locks.c */
+ extern __init void ceph_flock_init(void);
diff --git a/patches.fixes/ceph-fix-null-pointer-deref-when-debugging-is-enabled.patch b/patches.fixes/ceph-fix-null-pointer-deref-when-debugging-is-enabled.patch
new file mode 100644
index 0000000000..1a4080a69f
--- /dev/null
+++ b/patches.fixes/ceph-fix-null-pointer-deref-when-debugging-is-enabled.patch
@@ -0,0 +1,25 @@
+From: Jeff Layton <jlayton@kernel.org>
+Date: Tue, 23 Apr 2019 14:18:45 -0400
+Subject: ceph: fix NULL pointer deref when debugging is enabled
+Git-commit: 40e7e2c0e86464bca839cdf891bd58a6d41b60b4
+Patch-mainline: v5.2-rc1
+References: bsc#1138681
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Acked-by: Luis Henriques <lhenriques@suse.com>
+---
+ fs/ceph/file.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/ceph/file.c
++++ b/fs/ceph/file.c
+@@ -926,7 +926,7 @@ ceph_direct_read_write(struct kiocb *ioc
+
+ dout("sync_direct_%s on file %p %lld~%u snapc %p seq %lld\n",
+ (write ? "write" : "read"), file, pos, (unsigned)count,
+- snapc, snapc->seq);
++ snapc, snapc ? snapc->seq : 0);
+
+ ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + count);
+ if (ret < 0)
diff --git a/patches.fixes/ceph-fix-potential-use-after-free-in-ceph_mdsc_build_path.patch b/patches.fixes/ceph-fix-potential-use-after-free-in-ceph_mdsc_build_path.patch
new file mode 100644
index 0000000000..338983cd8e
--- /dev/null
+++ b/patches.fixes/ceph-fix-potential-use-after-free-in-ceph_mdsc_build_path.patch
@@ -0,0 +1,57 @@
+From: Jeff Layton <jlayton@kernel.org>
+Date: Fri, 26 Apr 2019 13:33:39 -0400
+Subject: ceph: fix potential use-after-free in ceph_mdsc_build_path
+Git-commit: 69a10fb3f4b8769ffd44e4eaa662ab691fa61f4c
+Patch-mainline: v5.2-rc1
+References: bsc#1138681
+
+temp is not defined outside of the RCU critical section here. Ensure
+we grab that value before we drop the rcu_read_lock.
+
+Reported-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Acked-by: Luis Henriques <lhenriques@suse.com>
+---
+ fs/ceph/mds_client.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/fs/ceph/mds_client.c
++++ b/fs/ceph/mds_client.c
+@@ -1883,13 +1883,14 @@ static inline u64 __get_oldest_tid(stru
+ * Encode hidden .snap dirs as a double /, i.e.
+ * foo/.snap/bar -> foo//bar
+ */
+-char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
++char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
+ int stop_on_nosnap)
+ {
+ struct dentry *temp;
+ char *path;
+ int len, pos;
+ unsigned seq;
++ u64 base;
+
+ if (!dentry)
+ return ERR_PTR(-EINVAL);
+@@ -1945,6 +1946,7 @@ retry:
+ path[--pos] = '/';
+ temp = temp->d_parent;
+ }
++ base = ceph_ino(d_inode(temp));
+ rcu_read_unlock();
+ if (pos != 0 || read_seqretry(&rename_lock, seq)) {
+ pr_err("build_path did not end path lookup where "
+@@ -1957,10 +1959,10 @@ retry:
+ goto retry;
+ }
+
+- *base = ceph_ino(d_inode(temp));
++ *pbase = base;
+ *plen = len;
+ dout("build_path on %p %d built %llx '%.*s'\n",
+- dentry, d_count(dentry), *base, len, path);
++ dentry, d_count(dentry), base, len, path);
+ return path;
+ }
+
diff --git a/patches.fixes/ceph-flush-dirty-inodes-before-proceeding-with-remount.patch b/patches.fixes/ceph-flush-dirty-inodes-before-proceeding-with-remount.patch
new file mode 100644
index 0000000000..5614ca34ae
--- /dev/null
+++ b/patches.fixes/ceph-flush-dirty-inodes-before-proceeding-with-remount.patch
@@ -0,0 +1,48 @@
+From: Jeff Layton <jlayton@kernel.org>
+Date: Tue, 7 May 2019 09:20:54 -0400
+Subject: ceph: flush dirty inodes before proceeding with remount
+Git-commit: 00abf69dd24f4444d185982379c5cc3bb7b6d1fc
+Patch-mainline: v5.2-rc1
+References: bsc#1138681
+
+xfstest generic/452 was triggering a "Busy inodes after umount" warning.
+ceph was allowing the mount to go read-only without first flushing out
+dirty inodes in the cache. Ensure we sync out the filesystem before
+allowing a remount to proceed.
+
+Cc: stable@vger.kernel.org
+Link: http://tracker.ceph.com/issues/39571
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Acked-by: Luis Henriques <lhenriques@suse.com>
+---
+ fs/ceph/super.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/fs/ceph/super.c b/fs/ceph/super.c
+index 6d5bb2f74612..01113c86e469 100644
+--- a/fs/ceph/super.c
++++ b/fs/ceph/super.c
+@@ -845,6 +845,12 @@ static void ceph_umount_begin(struct super_block *sb)
+ return;
+ }
+
++static int ceph_remount(struct super_block *sb, int *flags, char *data)
++{
++ sync_filesystem(sb);
++ return 0;
++}
++
+ static const struct super_operations ceph_super_ops = {
+ .alloc_inode = ceph_alloc_inode,
+ .destroy_inode = ceph_destroy_inode,
+@@ -852,6 +858,7 @@ static const struct super_operations ceph_super_ops = {
+ .drop_inode = ceph_drop_inode,
+ .sync_fs = ceph_sync_fs,
+ .put_super = ceph_put_super,
++ .remount_fs = ceph_remount,
+ .show_options = ceph_show_options,
+ .statfs = ceph_statfs,
+ .umount_begin = ceph_umount_begin,
+
diff --git a/patches.fixes/ceph-print-inode-number-in-_caps_issued_mask-debugging-messages.patch b/patches.fixes/ceph-print-inode-number-in-_caps_issued_mask-debugging-messages.patch
new file mode 100644
index 0000000000..a822ab0883
--- /dev/null
+++ b/patches.fixes/ceph-print-inode-number-in-_caps_issued_mask-debugging-messages.patch
@@ -0,0 +1,55 @@
+From: Jeff Layton <jlayton@kernel.org>
+Date: Tue, 23 Apr 2019 13:40:02 -0400
+Subject: ceph: print inode number in __caps_issued_mask debugging messages
+Git-commit: 5ddc61fc145861e4e542c9273a4088b627ba9b8d
+Patch-mainline: v5.2-rc1
+References: bsc#1138681
+
+To make it easier to correlate with MDS logs.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Acked-by: Luis Henriques <lhenriques@suse.com>
+---
+ fs/ceph/caps.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
+index 9e0b464d374f..72f8e1311392 100644
+--- a/fs/ceph/caps.c
++++ b/fs/ceph/caps.c
+@@ -892,8 +892,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
+ int have = ci->i_snap_caps;
+
+ if ((have & mask) == mask) {
+- dout("__ceph_caps_issued_mask %p snap issued %s"
+- " (mask %s)\n", &ci->vfs_inode,
++ dout("__ceph_caps_issued_mask ino 0x%lx snap issued %s"
++ " (mask %s)\n", ci->vfs_inode.i_ino,
+ ceph_cap_string(have),
+ ceph_cap_string(mask));
+ return 1;
+@@ -904,8 +904,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
+ if (!__cap_is_valid(cap))
+ continue;
+ if ((cap->issued & mask) == mask) {
+- dout("__ceph_caps_issued_mask %p cap %p issued %s"
+- " (mask %s)\n", &ci->vfs_inode, cap,
++ dout("__ceph_caps_issued_mask ino 0x%lx cap %p issued %s"
++ " (mask %s)\n", ci->vfs_inode.i_ino, cap,
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(mask));
+ if (touch)
+@@ -916,8 +916,8 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
+ /* does a combination of caps satisfy mask? */
+ have |= cap->issued;
+ if ((have & mask) == mask) {
+- dout("__ceph_caps_issued_mask %p combo issued %s"
+- " (mask %s)\n", &ci->vfs_inode,
++ dout("__ceph_caps_issued_mask ino 0x%lx combo issued %s"
++ " (mask %s)\n", ci->vfs_inode.i_ino,
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(mask));
+ if (touch) {
+
diff --git a/patches.fixes/ceph-quota-fix-quota-subdir-mounts.patch b/patches.fixes/ceph-quota-fix-quota-subdir-mounts.patch
new file mode 100644
index 0000000000..afd66f82cd
--- /dev/null
+++ b/patches.fixes/ceph-quota-fix-quota-subdir-mounts.patch
@@ -0,0 +1,347 @@
+From: Luis Henriques <lhenriques@suse.com>
+Date: Thu, 21 Mar 2019 10:20:10 +0000
+Subject: ceph: quota: fix quota subdir mounts
+Git-commit: 0c44a8e0fc55f56a70f72e67d7cc5b9341dae7d1
+Patch-mainline: v5.2-rc1
+References: bsc#1138681
+
+The CephFS kernel client does not enforce quotas set in a directory that
+isn't visible from the mount point. For example, given the path
+'/dir1/dir2', if quotas are set in 'dir1' and the filesystem is mounted with
+
+ mount -t ceph <server>:<port>:/dir1/ /mnt
+
+then the client won't be able to access 'dir1' inode, even if 'dir2' belongs
+to a quota realm that points to it.
+
+This patch fixes this issue by simply doing an MDS LOOKUPINO operation for
+unknown inodes. Any inode reference obtained this way will be added to a
+list in ceph_mds_client, and will only be released when the filesystem is
+umounted.
+
+Link: https://tracker.ceph.com/issues/38482
+Reported-by: Hendrik Peyerl <hpeyerl@plusline.net>
+Signed-off-by: Luis Henriques <lhenriques@suse.com>
+Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+---
+ fs/ceph/mds_client.c | 4 +
+ fs/ceph/mds_client.h | 18 +++++
+ fs/ceph/quota.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++---
+ fs/ceph/super.h | 1
+ 4 files changed, 190 insertions(+), 10 deletions(-)
+
+--- a/fs/ceph/mds_client.c
++++ b/fs/ceph/mds_client.c
+@@ -3701,6 +3701,8 @@ int ceph_mdsc_init(struct ceph_fs_client
+ mdsc->max_sessions = 0;
+ mdsc->stopping = 0;
+ atomic64_set(&mdsc->quotarealms_count, 0);
++ mdsc->quotarealms_inodes = RB_ROOT;
++ mutex_init(&mdsc->quotarealms_inodes_mutex);
+ mdsc->last_snap_seq = 0;
+ init_rwsem(&mdsc->snap_rwsem);
+ mdsc->snap_realms = RB_ROOT;
+@@ -3783,6 +3785,8 @@ void ceph_mdsc_pre_umount(struct ceph_md
+ * their inode/dcache refs
+ */
+ ceph_msgr_flush();
++
++ ceph_cleanup_quotarealms_inodes(mdsc);
+ }
+
+ /*
+--- a/fs/ceph/mds_client.h
++++ b/fs/ceph/mds_client.h
+@@ -310,6 +310,18 @@ struct ceph_pool_perm {
+ };
+
+ /*
++ * node for list of quotarealm inodes that are not visible from the filesystem
++ * mountpoint, but required to handle, e.g. quotas.
++ */
++struct ceph_quotarealm_inode {
++ struct rb_node node;
++ u64 ino;
++ unsigned long timeout; /* last time a lookup failed for this inode */
++ struct mutex mutex;
++ struct inode *inode;
++};
++
++/*
+ * mds client state
+ */
+ struct ceph_mds_client {
+@@ -328,6 +340,12 @@ struct ceph_mds_client {
+ int stopping; /* true if shutting down */
+
+ atomic64_t quotarealms_count; /* # realms with quota */
++ /*
++ * We keep a list of inodes we don't see in the mountpoint but that we
++ * need to track quota realms.
++ */
++ struct rb_root quotarealms_inodes;
++ struct mutex quotarealms_inodes_mutex;
+
+ /*
+ * snap_rwsem will cover cap linkage into snaprealms, and
+--- a/fs/ceph/quota.c
++++ b/fs/ceph/quota.c
+@@ -35,7 +35,16 @@ void ceph_adjust_quota_realms_count(stru
+ static inline bool ceph_has_realms_with_quotas(struct inode *inode)
+ {
+ struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
+- return atomic64_read(&mdsc->quotarealms_count) > 0;
++ struct super_block *sb = mdsc->fsc->sb;
++
++ if (atomic64_read(&mdsc->quotarealms_count) > 0)
++ return true;
++ /* if root is the real CephFS root, we don't have quota realms */
++ if (sb->s_root->d_inode &&
++ (sb->s_root->d_inode->i_ino == CEPH_INO_ROOT))
++ return false;
++ /* otherwise, we can't know for sure */
++ return true;
+ }
+
+ void ceph_handle_quota(struct ceph_mds_client *mdsc,
+@@ -81,6 +90,108 @@ void ceph_handle_quota(struct ceph_mds_c
+ iput(inode);
+ }
+
++static struct ceph_quotarealm_inode *
++find_quotarealm_inode(struct ceph_mds_client *mdsc, u64 ino)
++{
++ struct ceph_quotarealm_inode *qri = NULL;
++ struct rb_node **node, *parent = NULL;
++
++ mutex_lock(&mdsc->quotarealms_inodes_mutex);
++ node = &(mdsc->quotarealms_inodes.rb_node);
++ while (*node) {
++ parent = *node;
++ qri = container_of(*node, struct ceph_quotarealm_inode, node);
++
++ if (ino < qri->ino)
++ node = &((*node)->rb_left);
++ else if (ino > qri->ino)
++ node = &((*node)->rb_right);
++ else
++ break;
++ }
++ if (!qri || (qri->ino != ino)) {
++ /* Not found, create a new one and insert it */
++ qri = kmalloc(sizeof(*qri), GFP_KERNEL);
++ if (qri) {
++ qri->ino = ino;
++ qri->inode = NULL;
++ qri->timeout = 0;
++ mutex_init(&qri->mutex);
++ rb_link_node(&qri->node, parent, node);
++ rb_insert_color(&qri->node, &mdsc->quotarealms_inodes);
++ } else
++ pr_warn("Failed to alloc quotarealms_inode\n");
++ }
++ mutex_unlock(&mdsc->quotarealms_inodes_mutex);
++
++ return qri;
++}
++
++/*
++ * This function will try to lookup a realm inode which isn't visible in the
++ * filesystem mountpoint. A list of these kind of inodes (not visible) is
++ * maintained in the mdsc and freed only when the filesystem is umounted.
++ *
++ * Note that these inodes are kept in this list even if the lookup fails, which
++ * allows to prevent useless lookup requests.
++ */
++static struct inode *lookup_quotarealm_inode(struct ceph_mds_client *mdsc,
++ struct super_block *sb,
++ struct ceph_snap_realm *realm)
++{
++ struct ceph_quotarealm_inode *qri;
++ struct inode *in;
++
++ qri = find_quotarealm_inode(mdsc, realm->ino);
++ if (!qri)
++ return NULL;
++
++ mutex_lock(&qri->mutex);
++ if (qri->inode) {
++ /* A request has already returned the inode */
++ mutex_unlock(&qri->mutex);
++ return qri->inode;
++ }
++ /* Check if this inode lookup has failed recently */
++ if (qri->timeout &&
++ time_before_eq(jiffies, qri->timeout)) {
++ mutex_unlock(&qri->mutex);
++ return NULL;
++ }
++ in = ceph_lookup_inode(sb, realm->ino);
++ if (IS_ERR(in)) {
++ pr_warn("Can't lookup inode %llx (err: %ld)\n",
++ realm->ino, PTR_ERR(in));
++ qri->timeout = jiffies + msecs_to_jiffies(60 * 1000); /* XXX */
++ } else {
++ qri->timeout = 0;
++ qri->inode = in;
++ }
++ mutex_unlock(&qri->mutex);
++
++ return in;
++}
++
++void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc)
++{
++ struct ceph_quotarealm_inode *qri;
++ struct rb_node *node;
++
++ /*
++ * It should now be safe to clean quotarealms_inode tree without holding
++ * mdsc->quotarealms_inodes_mutex...
++ */
++ mutex_lock(&mdsc->quotarealms_inodes_mutex);
++ while (!RB_EMPTY_ROOT(&mdsc->quotarealms_inodes)) {
++ node = rb_first(&mdsc->quotarealms_inodes);
++ qri = rb_entry(node, struct ceph_quotarealm_inode, node);
++ rb_erase(node, &mdsc->quotarealms_inodes);
++ iput(qri->inode);
++ kfree(qri);
++ }
++ mutex_unlock(&mdsc->quotarealms_inodes_mutex);
++}
++
+ /*
+ * This function walks through the snaprealm for an inode and returns the
+ * ceph_snap_realm for the first snaprealm that has quotas set (either max_files
+@@ -89,9 +200,15 @@ void ceph_handle_quota(struct ceph_mds_c
+ *
+ * Note that the caller is responsible for calling ceph_put_snap_realm() on the
+ * returned realm.
++ *
++ * Callers of this function need to hold mdsc->snap_rwsem. However, if there's
++ * a need to do an inode lookup, this rwsem will be temporarily dropped. Hence
++ * the 'retry' argument: if rwsem needs to be dropped and 'retry' is 'false'
++ * this function will return -EAGAIN; otherwise, the snaprealms walk-through
++ * will be restarted.
+ */
+ static struct ceph_snap_realm *get_quota_realm(struct ceph_mds_client *mdsc,
+- struct inode *inode)
++ struct inode *inode, bool retry)
+ {
+ struct ceph_inode_info *ci = NULL;
+ struct ceph_snap_realm *realm, *next;
+@@ -101,6 +218,7 @@ static struct ceph_snap_realm *get_quota
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ return NULL;
+
++restart:
+ realm = ceph_inode(inode)->i_snap_realm;
+ if (realm)
+ ceph_get_snap_realm(mdsc, realm);
+@@ -108,11 +226,25 @@ static struct ceph_snap_realm *get_quota
+ pr_err_ratelimited("get_quota_realm: ino (%llx.%llx) "
+ "null i_snap_realm\n", ceph_vinop(inode));
+ while (realm) {
++ bool has_inode;
++
+ spin_lock(&realm->inodes_with_caps_lock);
+- in = realm->inode ? igrab(realm->inode) : NULL;
++ has_inode = realm->inode;
++ in = has_inode ? igrab(realm->inode) : NULL;
+ spin_unlock(&realm->inodes_with_caps_lock);
+- if (!in)
++ if (has_inode && !in)
+ break;
++ if (!in) {
++ up_read(&mdsc->snap_rwsem);
++ in = lookup_quotarealm_inode(mdsc, inode->i_sb, realm);
++ down_read(&mdsc->snap_rwsem);
++ if (IS_ERR_OR_NULL(in))
++ break;
++ ceph_put_snap_realm(mdsc, realm);
++ if (!retry)
++ return ERR_PTR(-EAGAIN);
++ goto restart;
++ }
+
+ ci = ceph_inode(in);
+ has_quota = __ceph_has_any_quota(ci);
+@@ -138,9 +270,22 @@ bool ceph_quota_is_same_realm(struct ino
+ struct ceph_snap_realm *old_realm, *new_realm;
+ bool is_same;
+
++restart:
++ /*
++ * We need to lookup 2 quota realms atomically, i.e. with snap_rwsem.
++ * However, get_quota_realm may drop it temporarily. By setting the
++ * 'retry' parameter to 'false', we'll get -EAGAIN if the rwsem was
++ * dropped and we can then restart the whole operation.
++ */
+ down_read(&mdsc->snap_rwsem);
+- old_realm = get_quota_realm(mdsc, old);
+- new_realm = get_quota_realm(mdsc, new);
++ old_realm = get_quota_realm(mdsc, old, true);
++ new_realm = get_quota_realm(mdsc, new, false);
++ if (PTR_ERR(new_realm) == -EAGAIN) {
++ up_read(&mdsc->snap_rwsem);
++ if (old_realm)
++ ceph_put_snap_realm(mdsc, old_realm);
++ goto restart;
++ }
+ is_same = (old_realm == new_realm);
+ up_read(&mdsc->snap_rwsem);
+
+@@ -179,6 +324,7 @@ static bool check_quota_exceeded(struct
+ return false;
+
+ down_read(&mdsc->snap_rwsem);
++restart:
+ realm = ceph_inode(inode)->i_snap_realm;
+ if (realm)
+ ceph_get_snap_realm(mdsc, realm);
+@@ -186,12 +332,23 @@ static bool check_quota_exceeded(struct
+ pr_err_ratelimited("check_quota_exceeded: ino (%llx.%llx) "
+ "null i_snap_realm\n", ceph_vinop(inode));
+ while (realm) {
++ bool has_inode;
++
+ spin_lock(&realm->inodes_with_caps_lock);
+- in = realm->inode ? igrab(realm->inode) : NULL;
++ has_inode = realm->inode;
++ in = has_inode ? igrab(realm->inode) : NULL;
+ spin_unlock(&realm->inodes_with_caps_lock);
+- if (!in)
++ if (has_inode && !in)
+ break;
+-
++ if (!in) {
++ up_read(&mdsc->snap_rwsem);
++ in = lookup_quotarealm_inode(mdsc, inode->i_sb, realm);
++ down_read(&mdsc->snap_rwsem);
++ if (IS_ERR_OR_NULL(in))
++ break;
++ ceph_put_snap_realm(mdsc, realm);
++ goto restart;
++ }
+ ci = ceph_inode(in);
+ spin_lock(&ci->i_ceph_lock);
+ if (op == QUOTA_CHECK_MAX_FILES_OP) {
+@@ -327,7 +484,7 @@ bool ceph_quota_update_statfs(struct cep
+ bool is_updated = false;
+
+ down_read(&mdsc->snap_rwsem);
+- realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root));
++ realm = get_quota_realm(mdsc, d_inode(fsc->sb->s_root), true);
+ up_read(&mdsc->snap_rwsem);
+ if (!realm)
+ return false;
+--- a/fs/ceph/super.h
++++ b/fs/ceph/super.h
+@@ -1108,5 +1108,6 @@ extern bool ceph_quota_is_max_bytes_appr
+ loff_t newlen);
+ extern bool ceph_quota_update_statfs(struct ceph_fs_client *fsc,
+ struct kstatfs *buf);
++extern void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc);
+
+ #endif /* _FS_CEPH_SUPER_H */
diff --git a/patches.fixes/ceph-remove-duplicated-filelock-ref-increase.patch b/patches.fixes/ceph-remove-duplicated-filelock-ref-increase.patch
new file mode 100644
index 0000000000..055628bcc5
--- /dev/null
+++ b/patches.fixes/ceph-remove-duplicated-filelock-ref-increase.patch
@@ -0,0 +1,53 @@
+From: Zhi Zhang <willzzhang@tencent.com>
+Date: Fri, 22 Mar 2019 14:16:33 +0800
+Subject: ceph: remove duplicated filelock ref increase
+Git-commit: 1b52931ca9b5b87e237c591f99201b6254c00809
+Patch-mainline: v5.2-rc1
+References: bsc#1138681
+
+Inode i_filelock_ref is increased in ceph_lock or ceph_flock, but it is
+increased again in ceph_lock_message. This results in this ref won't
+become zero. If CEPH_I_ERROR_FILELOCK flag is set in
+remove_session_caps once, this flag can't be cleared even if client is
+back to normal. So further file lock will return EIO.
+
+Signed-off-by: Zhi Zhang <zhang.david2011@gmail.com>
+Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Acked-by: Luis Henriques <lhenriques@suse.com>
+---
+ fs/ceph/locks.c | 13 -------------
+ 1 file changed, 13 deletions(-)
+
+diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c
+index 9dae2ec7e1fa..ac9b53b89365 100644
+--- a/fs/ceph/locks.c
++++ b/fs/ceph/locks.c
+@@ -237,15 +237,6 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
+ spin_lock(&ci->i_ceph_lock);
+ if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
+ err = -EIO;
+- } else if (op == CEPH_MDS_OP_SETFILELOCK) {
+- /*
+- * increasing i_filelock_ref closes race window between
+- * handling request reply and adding file_lock struct to
+- * inode. Otherwise, i_auth_cap may get trimmed in the
+- * window. Caller function will decrease the counter.
+- */
+- fl->fl_ops = &ceph_fl_lock_ops;
+- atomic_inc(&ci->i_filelock_ref);
+ }
+ spin_unlock(&ci->i_ceph_lock);
+ if (err < 0) {
+@@ -299,10 +290,6 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
+ spin_lock(&ci->i_ceph_lock);
+ if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
+ err = -EIO;
+- } else {
+- /* see comment in ceph_lock */
+- fl->fl_ops = &ceph_fl_lock_ops;
+- atomic_inc(&ci->i_filelock_ref);
+ }
+ spin_unlock(&ci->i_ceph_lock);
+ if (err < 0) {
+
diff --git a/patches.fixes/rbd-don-t-assert-on-writes-to-snapshots.patch b/patches.fixes/rbd-don-t-assert-on-writes-to-snapshots.patch
new file mode 100644
index 0000000000..401ea8ea6f
--- /dev/null
+++ b/patches.fixes/rbd-don-t-assert-on-writes-to-snapshots.patch
@@ -0,0 +1,44 @@
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Fri, 3 May 2019 17:27:03 +0200
+Subject: rbd: don't assert on writes to snapshots
+Git-commit: b91a7bdca4439e286f26cdd6c15ed338e6a9fda2
+Patch-mainline: v5.2-rc1
+References: bsc#1137985 bsc#1138681
+
+The check added in commit 721c7fc701c7 ("block: fail op_is_write()
+requests to read-only partitions") was lifted in commit a32e236eb93e
+("Partially revert "block: fail op_is_write() requests to read-only
+partitions""). Basic things like user triggered writes and discards
+are still caught, but internal kernel users can submit anything. In
+particular, ext4 will attempt to write to the superblock if it detects
+errors in the filesystem, even if the filesystem is mounted read-only
+on a read-only partition.
+
+The assert is overkill regardless.
+
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Acked-by: Luis Henriques <lhenriques@suse.com>
+---
+ drivers/block/rbd.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
+index 99de7166bf89..e5009a34f9c2 100644
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -3842,8 +3842,12 @@ static void rbd_queue_workfn(struct work_struct *work)
+ goto err_rq;
+ }
+
+- rbd_assert(op_type == OBJ_OP_READ ||
+- rbd_dev->spec->snap_id == CEPH_NOSNAP);
++ if (op_type != OBJ_OP_READ && rbd_dev->spec->snap_id != CEPH_NOSNAP) {
++ rbd_warn(rbd_dev, "%s on read-only snapshot",
++ obj_op_name(op_type));
++ result = -EIO;
++ goto err;
++ }
+
+ /*
+ * Quit early if the mapped snapshot no longer exists. It's
+
diff --git a/series.conf b/series.conf
index 94d35bd631..49c136ae5a 100644
--- a/series.conf
+++ b/series.conf
@@ -47027,6 +47027,14 @@
patches.drivers/media-atmel-atmel-isc-fix-INIT_WORK-misplacement.patch
patches.drivers/media-omap_vout-potential-buffer-overflow-in-vidioc_.patch
patches.drivers/media-davinci-vpbe-array-underflow-in-vpbe_enum_outp.patch
+ patches.fixes/ceph-remove-duplicated-filelock-ref-increase.patch
+ patches.fixes/ceph-factor-out-ceph_lookup_inode.patch
+ patches.fixes/ceph-quota-fix-quota-subdir-mounts.patch
+ patches.fixes/ceph-fix-null-pointer-deref-when-debugging-is-enabled.patch
+ patches.fixes/ceph-fix-potential-use-after-free-in-ceph_mdsc_build_path.patch
+ patches.fixes/ceph-print-inode-number-in-_caps_issued_mask-debugging-messages.patch
+ patches.fixes/rbd-don-t-assert-on-writes-to-snapshots.patch
+ patches.fixes/ceph-flush-dirty-inodes-before-proceeding-with-remount.patch
patches.fixes/nvme-fc-use-separate-work-queue-to-avoid-warning.patch
patches.arch/KVM-PPC-Book3S-HV-Avoid-lockdep-debugging-in-TCE-rea.patch
patches.drivers/ALSA-hda-realtek-Fixup-headphone-noise-via-runtime-s.patch