ceph: return -EIO if read/write against filp that lost file locks
After mds evicts session, file locks get lost sliently. It's not safe to let programs continue to do read/write. Signed-off-by: "Yan, Zheng" <zyan@redhat.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Родитель
d468e729b7
Коммит
ff5d913dfc
|
@ -2570,8 +2570,13 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got,
|
||||||
*
|
*
|
||||||
* FIXME: how does a 0 return differ from -EAGAIN?
|
* FIXME: how does a 0 return differ from -EAGAIN?
|
||||||
*/
|
*/
|
||||||
|
enum {
|
||||||
|
NON_BLOCKING = 1,
|
||||||
|
CHECK_FILELOCK = 2,
|
||||||
|
};
|
||||||
|
|
||||||
static int try_get_cap_refs(struct inode *inode, int need, int want,
|
static int try_get_cap_refs(struct inode *inode, int need, int want,
|
||||||
loff_t endoff, bool nonblock, int *got)
|
loff_t endoff, int flags, int *got)
|
||||||
{
|
{
|
||||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||||
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
|
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
|
||||||
|
@ -2586,6 +2591,13 @@ static int try_get_cap_refs(struct inode *inode, int need, int want,
|
||||||
again:
|
again:
|
||||||
spin_lock(&ci->i_ceph_lock);
|
spin_lock(&ci->i_ceph_lock);
|
||||||
|
|
||||||
|
if ((flags & CHECK_FILELOCK) &&
|
||||||
|
(ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK)) {
|
||||||
|
dout("try_get_cap_refs %p error filelock\n", inode);
|
||||||
|
ret = -EIO;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
/* make sure file is actually open */
|
/* make sure file is actually open */
|
||||||
file_wanted = __ceph_caps_file_wanted(ci);
|
file_wanted = __ceph_caps_file_wanted(ci);
|
||||||
if ((file_wanted & need) != need) {
|
if ((file_wanted & need) != need) {
|
||||||
|
@ -2647,7 +2659,7 @@ again:
|
||||||
* we can not call down_read() when
|
* we can not call down_read() when
|
||||||
* task isn't in TASK_RUNNING state
|
* task isn't in TASK_RUNNING state
|
||||||
*/
|
*/
|
||||||
if (nonblock) {
|
if (flags & NON_BLOCKING) {
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
@ -2752,7 +2764,8 @@ int ceph_try_get_caps(struct inode *inode, int need, int want,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = try_get_cap_refs(inode, need, want, 0, nonblock, got);
|
ret = try_get_cap_refs(inode, need, want, 0,
|
||||||
|
(nonblock ? NON_BLOCKING : 0), got);
|
||||||
return ret == -EAGAIN ? 0 : ret;
|
return ret == -EAGAIN ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2764,9 +2777,10 @@ int ceph_try_get_caps(struct inode *inode, int need, int want,
|
||||||
int ceph_get_caps(struct file *filp, int need, int want,
|
int ceph_get_caps(struct file *filp, int need, int want,
|
||||||
loff_t endoff, int *got, struct page **pinned_page)
|
loff_t endoff, int *got, struct page **pinned_page)
|
||||||
{
|
{
|
||||||
|
struct ceph_file_info *fi = filp->private_data;
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(filp);
|
||||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||||
int _got, ret;
|
int ret, _got, flags;
|
||||||
|
|
||||||
ret = ceph_pool_perm_check(inode, need);
|
ret = ceph_pool_perm_check(inode, need);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -2776,17 +2790,19 @@ int ceph_get_caps(struct file *filp, int need, int want,
|
||||||
if (endoff > 0)
|
if (endoff > 0)
|
||||||
check_max_size(inode, endoff);
|
check_max_size(inode, endoff);
|
||||||
|
|
||||||
|
flags = atomic_read(&fi->num_locks) ? CHECK_FILELOCK : 0;
|
||||||
_got = 0;
|
_got = 0;
|
||||||
ret = try_get_cap_refs(inode, need, want, endoff,
|
ret = try_get_cap_refs(inode, need, want, endoff,
|
||||||
false, &_got);
|
flags, &_got);
|
||||||
if (ret == -EAGAIN)
|
if (ret == -EAGAIN)
|
||||||
continue;
|
continue;
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||||
add_wait_queue(&ci->i_cap_wq, &wait);
|
add_wait_queue(&ci->i_cap_wq, &wait);
|
||||||
|
|
||||||
|
flags |= NON_BLOCKING;
|
||||||
while (!(ret = try_get_cap_refs(inode, need, want,
|
while (!(ret = try_get_cap_refs(inode, need, want,
|
||||||
endoff, true, &_got))) {
|
endoff, flags, &_got))) {
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
ret = -ERESTARTSYS;
|
ret = -ERESTARTSYS;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -32,14 +32,18 @@ void __init ceph_flock_init(void)
|
||||||
|
|
||||||
static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
|
static void ceph_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(src->fl_file);
|
struct ceph_file_info *fi = dst->fl_file->private_data;
|
||||||
|
struct inode *inode = file_inode(dst->fl_file);
|
||||||
atomic_inc(&ceph_inode(inode)->i_filelock_ref);
|
atomic_inc(&ceph_inode(inode)->i_filelock_ref);
|
||||||
|
atomic_inc(&fi->num_locks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ceph_fl_release_lock(struct file_lock *fl)
|
static void ceph_fl_release_lock(struct file_lock *fl)
|
||||||
{
|
{
|
||||||
|
struct ceph_file_info *fi = fl->fl_file->private_data;
|
||||||
struct inode *inode = file_inode(fl->fl_file);
|
struct inode *inode = file_inode(fl->fl_file);
|
||||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||||
|
atomic_dec(&fi->num_locks);
|
||||||
if (atomic_dec_and_test(&ci->i_filelock_ref)) {
|
if (atomic_dec_and_test(&ci->i_filelock_ref)) {
|
||||||
/* clear error when all locks are released */
|
/* clear error when all locks are released */
|
||||||
spin_lock(&ci->i_ceph_lock);
|
spin_lock(&ci->i_ceph_lock);
|
||||||
|
@ -73,7 +77,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct inode *inode,
|
||||||
* window. Caller function will decrease the counter.
|
* window. Caller function will decrease the counter.
|
||||||
*/
|
*/
|
||||||
fl->fl_ops = &ceph_fl_lock_ops;
|
fl->fl_ops = &ceph_fl_lock_ops;
|
||||||
atomic_inc(&ceph_inode(inode)->i_filelock_ref);
|
fl->fl_ops->fl_copy_lock(fl, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK)
|
if (operation != CEPH_MDS_OP_SETFILELOCK || cmd == CEPH_LOCK_UNLOCK)
|
||||||
|
|
|
@ -707,6 +707,7 @@ struct ceph_file_info {
|
||||||
struct list_head rw_contexts;
|
struct list_head rw_contexts;
|
||||||
|
|
||||||
errseq_t meta_err;
|
errseq_t meta_err;
|
||||||
|
atomic_t num_locks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ceph_dir_file_info {
|
struct ceph_dir_file_info {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче