]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ceph: fix handling of "meta" errors
authorJeff Layton <jlayton@kernel.org>
Thu, 7 Oct 2021 18:19:49 +0000 (14:19 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 27 Oct 2021 07:54:27 +0000 (09:54 +0200)
commit 1bd85aa65d0e7b5e4d09240f492f37c569fdd431 upstream.

Currently, we check the wb_err too early for directories, before all of
the unsafe child requests have been waited on. In order to fix that we
need to check the mapping->wb_err later nearer to the end of ceph_fsync.

We also have an overly-complex method for tracking errors after
blocklisting. The errors recorded in cleanup_session_requests go to a
completely separate field in the inode, but we end up reporting them the
same way we would for any other error (in fsync).

There's no real benefit to tracking these errors in two different
places, since the only reporting mechanism for them is in fsync, and
we'd need to advance them both every time.

Given that, we can just remove i_meta_err, and convert the places that
used it to instead just use mapping->wb_err instead. That also fixes
the original problem by ensuring that we do a check_and_advance of the
wb_err at the end of the fsync op.

Cc: stable@vger.kernel.org
URL: https://tracker.ceph.com/issues/52864
Reported-by: Patrick Donnelly <pdonnell@redhat.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ceph/caps.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/super.h

index 0fad044a5752b73ebfd80b39e8f2d71f800e60e6..06e9b26bf277a196643d54e6629570aeb09b04dd 100644 (file)
@@ -2249,7 +2249,6 @@ static int unsafe_request_wait(struct inode *inode)
 
 int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       struct ceph_file_info *fi = file->private_data;
        struct inode *inode = file->f_mapping->host;
        struct ceph_inode_info *ci = ceph_inode(inode);
        u64 flush_tid;
@@ -2280,14 +2279,9 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        if (err < 0)
                ret = err;
 
-       if (errseq_check(&ci->i_meta_err, READ_ONCE(fi->meta_err))) {
-               spin_lock(&file->f_lock);
-               err = errseq_check_and_advance(&ci->i_meta_err,
-                                              &fi->meta_err);
-               spin_unlock(&file->f_lock);
-               if (err < 0)
-                       ret = err;
-       }
+       err = file_check_and_advance_wb_err(file);
+       if (err < 0)
+               ret = err;
 out:
        dout("fsync %p%s result=%d\n", inode, datasync ? " datasync" : "", ret);
        return ret;
index 34785a203461d9fa5b3acfc570f9a4a855c99f13..aa1eac6d89f2e436cfe155389099f678cb216c54 100644 (file)
@@ -234,7 +234,6 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
        fi->fmode = fmode;
        spin_lock_init(&fi->rw_contexts_lock);
        INIT_LIST_HEAD(&fi->rw_contexts);
-       fi->meta_err = errseq_sample(&ci->i_meta_err);
        fi->filp_gen = READ_ONCE(ceph_inode_to_client(inode)->filp_gen);
 
        return 0;
index 5beebbbb42f099ab887a0f1dd6ae1f4d8a6b2b2a..af85a72376040ffef4c9287a7f14604a468d1233 100644 (file)
@@ -515,8 +515,6 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
 
        ceph_fscache_inode_init(ci);
 
-       ci->i_meta_err = 0;
-
        return &ci->vfs_inode;
 }
 
index 1ef370913c0077504395fd88a4d28f78fcf24744..37fb71797b341007cedc5ebb2d58726df56bf136 100644 (file)
@@ -1272,7 +1272,6 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc,
 {
        struct ceph_mds_request *req;
        struct rb_node *p;
-       struct ceph_inode_info *ci;
 
        dout("cleanup_session_requests mds%d\n", session->s_mds);
        mutex_lock(&mdsc->mutex);
@@ -1281,16 +1280,10 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc,
                                       struct ceph_mds_request, r_unsafe_item);
                pr_warn_ratelimited(" dropping unsafe request %llu\n",
                                    req->r_tid);
-               if (req->r_target_inode) {
-                       /* dropping unsafe change of inode's attributes */
-                       ci = ceph_inode(req->r_target_inode);
-                       errseq_set(&ci->i_meta_err, -EIO);
-               }
-               if (req->r_unsafe_dir) {
-                       /* dropping unsafe directory operation */
-                       ci = ceph_inode(req->r_unsafe_dir);
-                       errseq_set(&ci->i_meta_err, -EIO);
-               }
+               if (req->r_target_inode)
+                       mapping_set_error(req->r_target_inode->i_mapping, -EIO);
+               if (req->r_unsafe_dir)
+                       mapping_set_error(req->r_unsafe_dir->i_mapping, -EIO);
                __unregister_request(mdsc, req);
        }
        /* zero r_attempts, so kick_requests() will re-send requests */
@@ -1436,7 +1429,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
                spin_unlock(&mdsc->cap_dirty_lock);
 
                if (dirty_dropped) {
-                       errseq_set(&ci->i_meta_err, -EIO);
+                       mapping_set_error(inode->i_mapping, -EIO);
 
                        if (ci->i_wrbuffer_ref_head == 0 &&
                            ci->i_wr_ref == 0 &&
index 8ffc8e88dd3d2cac396fdc03b490078430807c82..6db7b3387e1cc60e87c14891088f7aa8712076c3 100644 (file)
@@ -402,8 +402,6 @@ struct ceph_inode_info {
        struct fscache_cookie *fscache;
        u32 i_fscache_gen;
 #endif
-       errseq_t i_meta_err;
-
        struct inode vfs_inode; /* at end */
 };
 
@@ -712,7 +710,6 @@ struct ceph_file_info {
        spinlock_t rw_contexts_lock;
        struct list_head rw_contexts;
 
-       errseq_t meta_err;
        u32 filp_gen;
        atomic_t num_locks;
 };