summaryrefslogtreecommitdiffstats
path: root/fs/ceph/addr.c
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2016-05-10 06:40:28 -0400
committerIlya Dryomov <idryomov@gmail.com>2016-05-25 19:15:39 -0400
commit4f7e89f6ace0f6cd2f20110efd2d405e26bcbf31 (patch)
tree4750ff4879c8c2f66a6f2f2e45ce8a347ca68122 /fs/ceph/addr.c
parent3b33f692c84c28cc8178aaeeb9264d82b48787f1 (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.c66
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
1318static 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
1325static 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;
1405out_inline:
1406 dout("filemap_fault %p %llu~%zd read inline data ret %d\n",
1407 inode, off, (size_t)PAGE_SIZE, ret);
1395 } 1408 }
1396out: 1409out_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);
1501out_free: 1512out_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;