diff options
author | Yan, Zheng <zyan@redhat.com> | 2016-05-10 06:40:28 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2016-05-25 19:15:39 -0400 |
commit | 4f7e89f6ace0f6cd2f20110efd2d405e26bcbf31 (patch) | |
tree | 4750ff4879c8c2f66a6f2f2e45ce8a347ca68122 /fs/ceph/addr.c | |
parent | 3b33f692c84c28cc8178aaeeb9264d82b48787f1 (diff) |
ceph: block non-fatal signals for fault/page_mkwrite
Fault and page_mkwrite are supposed to be uninterruptable. But they
call ceph functions that are interruptible. So they should block
signals before calling functions that are interruptible
Signed-off-by: Yan, Zheng <zyan@redhat.com>
Diffstat (limited to 'fs/ceph/addr.c')
-rw-r--r-- | fs/ceph/addr.c | 66 |
1 files changed, 39 insertions, 27 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index d52e3bcfda7c..3e204b9ff9f7 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
@@ -1315,6 +1315,17 @@ const struct address_space_operations ceph_aops = { | |||
1315 | .direct_IO = ceph_direct_io, | 1315 | .direct_IO = ceph_direct_io, |
1316 | }; | 1316 | }; |
1317 | 1317 | ||
1318 | static void ceph_block_sigs(sigset_t *oldset) | ||
1319 | { | ||
1320 | sigset_t mask; | ||
1321 | siginitsetinv(&mask, sigmask(SIGKILL)); | ||
1322 | sigprocmask(SIG_BLOCK, &mask, oldset); | ||
1323 | } | ||
1324 | |||
1325 | static void ceph_restore_sigs(sigset_t *oldset) | ||
1326 | { | ||
1327 | sigprocmask(SIG_SETMASK, oldset, NULL); | ||
1328 | } | ||
1318 | 1329 | ||
1319 | /* | 1330 | /* |
1320 | * vm ops | 1331 | * vm ops |
@@ -1327,6 +1338,9 @@ static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1327 | struct page *pinned_page = NULL; | 1338 | struct page *pinned_page = NULL; |
1328 | loff_t off = vmf->pgoff << PAGE_SHIFT; | 1339 | loff_t off = vmf->pgoff << PAGE_SHIFT; |
1329 | int want, got, ret; | 1340 | int want, got, ret; |
1341 | sigset_t oldset; | ||
1342 | |||
1343 | ceph_block_sigs(&oldset); | ||
1330 | 1344 | ||
1331 | dout("filemap_fault %p %llx.%llx %llu~%zd trying to get caps\n", | 1345 | dout("filemap_fault %p %llx.%llx %llu~%zd trying to get caps\n", |
1332 | inode, ceph_vinop(inode), off, (size_t)PAGE_SIZE); | 1346 | inode, ceph_vinop(inode), off, (size_t)PAGE_SIZE); |
@@ -1334,16 +1348,12 @@ static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1334 | want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO; | 1348 | want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO; |
1335 | else | 1349 | else |
1336 | want = CEPH_CAP_FILE_CACHE; | 1350 | want = CEPH_CAP_FILE_CACHE; |
1337 | while (1) { | 1351 | |
1338 | got = 0; | 1352 | got = 0; |
1339 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, | 1353 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, -1, &got, &pinned_page); |
1340 | -1, &got, &pinned_page); | 1354 | if (ret < 0) { |
1341 | if (ret == 0) | 1355 | ret = VM_FAULT_SIGBUS; |
1342 | break; | 1356 | goto out_restore; |
1343 | if (ret != -ERESTARTSYS) { | ||
1344 | WARN_ON(1); | ||
1345 | return VM_FAULT_SIGBUS; | ||
1346 | } | ||
1347 | } | 1357 | } |
1348 | dout("filemap_fault %p %llu~%zd got cap refs on %s\n", | 1358 | dout("filemap_fault %p %llu~%zd got cap refs on %s\n", |
1349 | inode, off, (size_t)PAGE_SIZE, ceph_cap_string(got)); | 1359 | inode, off, (size_t)PAGE_SIZE, ceph_cap_string(got)); |
@@ -1361,7 +1371,7 @@ static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1361 | ceph_put_cap_refs(ci, got); | 1371 | ceph_put_cap_refs(ci, got); |
1362 | 1372 | ||
1363 | if (ret != -EAGAIN) | 1373 | if (ret != -EAGAIN) |
1364 | return ret; | 1374 | goto out_restore; |
1365 | 1375 | ||
1366 | /* read inline data */ | 1376 | /* read inline data */ |
1367 | if (off >= PAGE_SIZE) { | 1377 | if (off >= PAGE_SIZE) { |
@@ -1375,7 +1385,7 @@ static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1375 | ~__GFP_FS)); | 1385 | ~__GFP_FS)); |
1376 | if (!page) { | 1386 | if (!page) { |
1377 | ret = VM_FAULT_OOM; | 1387 | ret = VM_FAULT_OOM; |
1378 | goto out; | 1388 | goto out_inline; |
1379 | } | 1389 | } |
1380 | ret1 = __ceph_do_getattr(inode, page, | 1390 | ret1 = __ceph_do_getattr(inode, page, |
1381 | CEPH_STAT_CAP_INLINE_DATA, true); | 1391 | CEPH_STAT_CAP_INLINE_DATA, true); |
@@ -1383,7 +1393,7 @@ static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1383 | unlock_page(page); | 1393 | unlock_page(page); |
1384 | put_page(page); | 1394 | put_page(page); |
1385 | ret = VM_FAULT_SIGBUS; | 1395 | ret = VM_FAULT_SIGBUS; |
1386 | goto out; | 1396 | goto out_inline; |
1387 | } | 1397 | } |
1388 | if (ret1 < PAGE_SIZE) | 1398 | if (ret1 < PAGE_SIZE) |
1389 | zero_user_segment(page, ret1, PAGE_SIZE); | 1399 | zero_user_segment(page, ret1, PAGE_SIZE); |
@@ -1392,10 +1402,12 @@ static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1392 | SetPageUptodate(page); | 1402 | SetPageUptodate(page); |
1393 | vmf->page = page; | 1403 | vmf->page = page; |
1394 | ret = VM_FAULT_MAJOR | VM_FAULT_LOCKED; | 1404 | ret = VM_FAULT_MAJOR | VM_FAULT_LOCKED; |
1405 | out_inline: | ||
1406 | dout("filemap_fault %p %llu~%zd read inline data ret %d\n", | ||
1407 | inode, off, (size_t)PAGE_SIZE, ret); | ||
1395 | } | 1408 | } |
1396 | out: | 1409 | out_restore: |
1397 | dout("filemap_fault %p %llu~%zd read inline data ret %d\n", | 1410 | ceph_restore_sigs(&oldset); |
1398 | inode, off, (size_t)PAGE_SIZE, ret); | ||
1399 | return ret; | 1411 | return ret; |
1400 | } | 1412 | } |
1401 | 1413 | ||
@@ -1413,11 +1425,14 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1413 | loff_t size = i_size_read(inode); | 1425 | loff_t size = i_size_read(inode); |
1414 | size_t len; | 1426 | size_t len; |
1415 | int want, got, ret; | 1427 | int want, got, ret; |
1428 | sigset_t oldset; | ||
1416 | 1429 | ||
1417 | prealloc_cf = ceph_alloc_cap_flush(); | 1430 | prealloc_cf = ceph_alloc_cap_flush(); |
1418 | if (!prealloc_cf) | 1431 | if (!prealloc_cf) |
1419 | return VM_FAULT_SIGBUS; | 1432 | return VM_FAULT_SIGBUS; |
1420 | 1433 | ||
1434 | ceph_block_sigs(&oldset); | ||
1435 | |||
1421 | if (ci->i_inline_version != CEPH_INLINE_NONE) { | 1436 | if (ci->i_inline_version != CEPH_INLINE_NONE) { |
1422 | struct page *locked_page = NULL; | 1437 | struct page *locked_page = NULL; |
1423 | if (off == 0) { | 1438 | if (off == 0) { |
@@ -1444,17 +1459,13 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1444 | want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO; | 1459 | want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO; |
1445 | else | 1460 | else |
1446 | want = CEPH_CAP_FILE_BUFFER; | 1461 | want = CEPH_CAP_FILE_BUFFER; |
1447 | while (1) { | 1462 | |
1448 | got = 0; | 1463 | got = 0; |
1449 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, off + len, | 1464 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, off + len, |
1450 | &got, NULL); | 1465 | &got, NULL); |
1451 | if (ret == 0) | 1466 | if (ret < 0) { |
1452 | break; | 1467 | ret = VM_FAULT_SIGBUS; |
1453 | if (ret != -ERESTARTSYS) { | 1468 | goto out_free; |
1454 | WARN_ON(1); | ||
1455 | ret = VM_FAULT_SIGBUS; | ||
1456 | goto out_free; | ||
1457 | } | ||
1458 | } | 1469 | } |
1459 | dout("page_mkwrite %p %llu~%zd got cap refs on %s\n", | 1470 | dout("page_mkwrite %p %llu~%zd got cap refs on %s\n", |
1460 | inode, off, len, ceph_cap_string(got)); | 1471 | inode, off, len, ceph_cap_string(got)); |
@@ -1499,6 +1510,7 @@ out: | |||
1499 | inode, off, len, ceph_cap_string(got), ret); | 1510 | inode, off, len, ceph_cap_string(got), ret); |
1500 | ceph_put_cap_refs(ci, got); | 1511 | ceph_put_cap_refs(ci, got); |
1501 | out_free: | 1512 | out_free: |
1513 | ceph_restore_sigs(&oldset); | ||
1502 | ceph_free_cap_flush(prealloc_cf); | 1514 | ceph_free_cap_flush(prealloc_cf); |
1503 | 1515 | ||
1504 | return ret; | 1516 | return ret; |