ceph: fix handling of "meta" errors
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>
This commit is contained in:
Родитель
98d0a6fb73
Коммит
1bd85aa65d
|
@ -2330,7 +2330,6 @@ retry:
|
||||||
|
|
||||||
int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
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 inode *inode = file->f_mapping->host;
|
||||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||||
u64 flush_tid;
|
u64 flush_tid;
|
||||||
|
@ -2365,14 +2364,9 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
ret = err;
|
ret = err;
|
||||||
|
|
||||||
if (errseq_check(&ci->i_meta_err, READ_ONCE(fi->meta_err))) {
|
err = file_check_and_advance_wb_err(file);
|
||||||
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)
|
if (err < 0)
|
||||||
ret = err;
|
ret = err;
|
||||||
}
|
|
||||||
out:
|
out:
|
||||||
dout("fsync %p%s result=%d\n", inode, datasync ? " datasync" : "", ret);
|
dout("fsync %p%s result=%d\n", inode, datasync ? " datasync" : "", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -233,7 +233,6 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
|
||||||
|
|
||||||
spin_lock_init(&fi->rw_contexts_lock);
|
spin_lock_init(&fi->rw_contexts_lock);
|
||||||
INIT_LIST_HEAD(&fi->rw_contexts);
|
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);
|
fi->filp_gen = READ_ONCE(ceph_inode_to_client(inode)->filp_gen);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -541,8 +541,6 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
|
||||||
|
|
||||||
ceph_fscache_inode_init(ci);
|
ceph_fscache_inode_init(ci);
|
||||||
|
|
||||||
ci->i_meta_err = 0;
|
|
||||||
|
|
||||||
return &ci->vfs_inode;
|
return &ci->vfs_inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1493,7 +1493,6 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc,
|
||||||
{
|
{
|
||||||
struct ceph_mds_request *req;
|
struct ceph_mds_request *req;
|
||||||
struct rb_node *p;
|
struct rb_node *p;
|
||||||
struct ceph_inode_info *ci;
|
|
||||||
|
|
||||||
dout("cleanup_session_requests mds%d\n", session->s_mds);
|
dout("cleanup_session_requests mds%d\n", session->s_mds);
|
||||||
mutex_lock(&mdsc->mutex);
|
mutex_lock(&mdsc->mutex);
|
||||||
|
@ -1502,16 +1501,10 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc,
|
||||||
struct ceph_mds_request, r_unsafe_item);
|
struct ceph_mds_request, r_unsafe_item);
|
||||||
pr_warn_ratelimited(" dropping unsafe request %llu\n",
|
pr_warn_ratelimited(" dropping unsafe request %llu\n",
|
||||||
req->r_tid);
|
req->r_tid);
|
||||||
if (req->r_target_inode) {
|
if (req->r_target_inode)
|
||||||
/* dropping unsafe change of inode's attributes */
|
mapping_set_error(req->r_target_inode->i_mapping, -EIO);
|
||||||
ci = ceph_inode(req->r_target_inode);
|
if (req->r_unsafe_dir)
|
||||||
errseq_set(&ci->i_meta_err, -EIO);
|
mapping_set_error(req->r_unsafe_dir->i_mapping, -EIO);
|
||||||
}
|
|
||||||
if (req->r_unsafe_dir) {
|
|
||||||
/* dropping unsafe directory operation */
|
|
||||||
ci = ceph_inode(req->r_unsafe_dir);
|
|
||||||
errseq_set(&ci->i_meta_err, -EIO);
|
|
||||||
}
|
|
||||||
__unregister_request(mdsc, req);
|
__unregister_request(mdsc, req);
|
||||||
}
|
}
|
||||||
/* zero r_attempts, so kick_requests() will re-send requests */
|
/* zero r_attempts, so kick_requests() will re-send requests */
|
||||||
|
@ -1678,7 +1671,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
|
||||||
spin_unlock(&mdsc->cap_dirty_lock);
|
spin_unlock(&mdsc->cap_dirty_lock);
|
||||||
|
|
||||||
if (dirty_dropped) {
|
if (dirty_dropped) {
|
||||||
errseq_set(&ci->i_meta_err, -EIO);
|
mapping_set_error(inode->i_mapping, -EIO);
|
||||||
|
|
||||||
if (ci->i_wrbuffer_ref_head == 0 &&
|
if (ci->i_wrbuffer_ref_head == 0 &&
|
||||||
ci->i_wr_ref == 0 &&
|
ci->i_wr_ref == 0 &&
|
||||||
|
|
|
@ -429,8 +429,6 @@ struct ceph_inode_info {
|
||||||
#ifdef CONFIG_CEPH_FSCACHE
|
#ifdef CONFIG_CEPH_FSCACHE
|
||||||
struct fscache_cookie *fscache;
|
struct fscache_cookie *fscache;
|
||||||
#endif
|
#endif
|
||||||
errseq_t i_meta_err;
|
|
||||||
|
|
||||||
struct inode vfs_inode; /* at end */
|
struct inode vfs_inode; /* at end */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -774,7 +772,6 @@ struct ceph_file_info {
|
||||||
spinlock_t rw_contexts_lock;
|
spinlock_t rw_contexts_lock;
|
||||||
struct list_head rw_contexts;
|
struct list_head rw_contexts;
|
||||||
|
|
||||||
errseq_t meta_err;
|
|
||||||
u32 filp_gen;
|
u32 filp_gen;
|
||||||
atomic_t num_locks;
|
atomic_t num_locks;
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче