diff options
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/addr.c | 38 | ||||
-rw-r--r-- | fs/ceph/caps.c | 51 | ||||
-rw-r--r-- | fs/ceph/dir.c | 48 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 61 | ||||
-rw-r--r-- | fs/ceph/strings.c | 1 | ||||
-rw-r--r-- | fs/ceph/super.c | 56 | ||||
-rw-r--r-- | fs/ceph/super.h | 4 | ||||
-rw-r--r-- | fs/ceph/xattr.c | 23 |
8 files changed, 190 insertions, 92 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 155ab9c0246b..e162bcd105ee 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
@@ -1146,6 +1146,10 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, | |||
1146 | inode, page, (int)pos, (int)len); | 1146 | inode, page, (int)pos, (int)len); |
1147 | 1147 | ||
1148 | r = ceph_update_writeable_page(file, pos, len, page); | 1148 | r = ceph_update_writeable_page(file, pos, len, page); |
1149 | if (r < 0) | ||
1150 | page_cache_release(page); | ||
1151 | else | ||
1152 | *pagep = page; | ||
1149 | } while (r == -EAGAIN); | 1153 | } while (r == -EAGAIN); |
1150 | 1154 | ||
1151 | return r; | 1155 | return r; |
@@ -1534,19 +1538,27 @@ int ceph_uninline_data(struct file *filp, struct page *locked_page) | |||
1534 | 1538 | ||
1535 | osd_req_op_extent_osd_data_pages(req, 1, &page, len, 0, false, false); | 1539 | osd_req_op_extent_osd_data_pages(req, 1, &page, len, 0, false, false); |
1536 | 1540 | ||
1537 | err = osd_req_op_xattr_init(req, 0, CEPH_OSD_OP_CMPXATTR, | 1541 | { |
1538 | "inline_version", &inline_version, | 1542 | __le64 xattr_buf = cpu_to_le64(inline_version); |
1539 | sizeof(inline_version), | 1543 | err = osd_req_op_xattr_init(req, 0, CEPH_OSD_OP_CMPXATTR, |
1540 | CEPH_OSD_CMPXATTR_OP_GT, | 1544 | "inline_version", &xattr_buf, |
1541 | CEPH_OSD_CMPXATTR_MODE_U64); | 1545 | sizeof(xattr_buf), |
1542 | if (err) | 1546 | CEPH_OSD_CMPXATTR_OP_GT, |
1543 | goto out_put; | 1547 | CEPH_OSD_CMPXATTR_MODE_U64); |
1544 | 1548 | if (err) | |
1545 | err = osd_req_op_xattr_init(req, 2, CEPH_OSD_OP_SETXATTR, | 1549 | goto out_put; |
1546 | "inline_version", &inline_version, | 1550 | } |
1547 | sizeof(inline_version), 0, 0); | 1551 | |
1548 | if (err) | 1552 | { |
1549 | goto out_put; | 1553 | char xattr_buf[32]; |
1554 | int xattr_len = snprintf(xattr_buf, sizeof(xattr_buf), | ||
1555 | "%llu", inline_version); | ||
1556 | err = osd_req_op_xattr_init(req, 2, CEPH_OSD_OP_SETXATTR, | ||
1557 | "inline_version", | ||
1558 | xattr_buf, xattr_len, 0, 0); | ||
1559 | if (err) | ||
1560 | goto out_put; | ||
1561 | } | ||
1550 | 1562 | ||
1551 | ceph_osdc_build_request(req, 0, NULL, CEPH_NOSNAP, &inode->i_mtime); | 1563 | ceph_osdc_build_request(req, 0, NULL, CEPH_NOSNAP, &inode->i_mtime); |
1552 | err = ceph_osdc_start_request(&fsc->client->osdc, req, false); | 1564 | err = ceph_osdc_start_request(&fsc->client->osdc, req, false); |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 8172775428a0..11631c4c7d14 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -896,6 +896,18 @@ int ceph_is_any_caps(struct inode *inode) | |||
896 | return ret; | 896 | return ret; |
897 | } | 897 | } |
898 | 898 | ||
899 | static void drop_inode_snap_realm(struct ceph_inode_info *ci) | ||
900 | { | ||
901 | struct ceph_snap_realm *realm = ci->i_snap_realm; | ||
902 | spin_lock(&realm->inodes_with_caps_lock); | ||
903 | list_del_init(&ci->i_snap_realm_item); | ||
904 | ci->i_snap_realm_counter++; | ||
905 | ci->i_snap_realm = NULL; | ||
906 | spin_unlock(&realm->inodes_with_caps_lock); | ||
907 | ceph_put_snap_realm(ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc, | ||
908 | realm); | ||
909 | } | ||
910 | |||
899 | /* | 911 | /* |
900 | * Remove a cap. Take steps to deal with a racing iterate_session_caps. | 912 | * Remove a cap. Take steps to deal with a racing iterate_session_caps. |
901 | * | 913 | * |
@@ -946,15 +958,13 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) | |||
946 | if (removed) | 958 | if (removed) |
947 | ceph_put_cap(mdsc, cap); | 959 | ceph_put_cap(mdsc, cap); |
948 | 960 | ||
949 | if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) { | 961 | /* when reconnect denied, we remove session caps forcibly, |
950 | struct ceph_snap_realm *realm = ci->i_snap_realm; | 962 | * i_wr_ref can be non-zero. If there are ongoing write, |
951 | spin_lock(&realm->inodes_with_caps_lock); | 963 | * keep i_snap_realm. |
952 | list_del_init(&ci->i_snap_realm_item); | 964 | */ |
953 | ci->i_snap_realm_counter++; | 965 | if (!__ceph_is_any_caps(ci) && ci->i_wr_ref == 0 && ci->i_snap_realm) |
954 | ci->i_snap_realm = NULL; | 966 | drop_inode_snap_realm(ci); |
955 | spin_unlock(&realm->inodes_with_caps_lock); | 967 | |
956 | ceph_put_snap_realm(mdsc, realm); | ||
957 | } | ||
958 | if (!__ceph_is_any_real_caps(ci)) | 968 | if (!__ceph_is_any_real_caps(ci)) |
959 | __cap_delay_cancel(mdsc, ci); | 969 | __cap_delay_cancel(mdsc, ci); |
960 | } | 970 | } |
@@ -1394,6 +1404,13 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | |||
1394 | int was = ci->i_dirty_caps; | 1404 | int was = ci->i_dirty_caps; |
1395 | int dirty = 0; | 1405 | int dirty = 0; |
1396 | 1406 | ||
1407 | if (!ci->i_auth_cap) { | ||
1408 | pr_warn("__mark_dirty_caps %p %llx mask %s, " | ||
1409 | "but no auth cap (session was closed?)\n", | ||
1410 | inode, ceph_ino(inode), ceph_cap_string(mask)); | ||
1411 | return 0; | ||
1412 | } | ||
1413 | |||
1397 | dout("__mark_dirty_caps %p %s dirty %s -> %s\n", &ci->vfs_inode, | 1414 | dout("__mark_dirty_caps %p %s dirty %s -> %s\n", &ci->vfs_inode, |
1398 | ceph_cap_string(mask), ceph_cap_string(was), | 1415 | ceph_cap_string(mask), ceph_cap_string(was), |
1399 | ceph_cap_string(was | mask)); | 1416 | ceph_cap_string(was | mask)); |
@@ -1404,7 +1421,6 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | |||
1404 | ci->i_snap_realm->cached_context); | 1421 | ci->i_snap_realm->cached_context); |
1405 | dout(" inode %p now dirty snapc %p auth cap %p\n", | 1422 | dout(" inode %p now dirty snapc %p auth cap %p\n", |
1406 | &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap); | 1423 | &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap); |
1407 | WARN_ON(!ci->i_auth_cap); | ||
1408 | BUG_ON(!list_empty(&ci->i_dirty_item)); | 1424 | BUG_ON(!list_empty(&ci->i_dirty_item)); |
1409 | spin_lock(&mdsc->cap_dirty_lock); | 1425 | spin_lock(&mdsc->cap_dirty_lock); |
1410 | list_add(&ci->i_dirty_item, &mdsc->cap_dirty); | 1426 | list_add(&ci->i_dirty_item, &mdsc->cap_dirty); |
@@ -1545,7 +1561,19 @@ retry_locked: | |||
1545 | if (!mdsc->stopping && inode->i_nlink > 0) { | 1561 | if (!mdsc->stopping && inode->i_nlink > 0) { |
1546 | if (want) { | 1562 | if (want) { |
1547 | retain |= CEPH_CAP_ANY; /* be greedy */ | 1563 | retain |= CEPH_CAP_ANY; /* be greedy */ |
1564 | } else if (S_ISDIR(inode->i_mode) && | ||
1565 | (issued & CEPH_CAP_FILE_SHARED) && | ||
1566 | __ceph_dir_is_complete(ci)) { | ||
1567 | /* | ||
1568 | * If a directory is complete, we want to keep | ||
1569 | * the exclusive cap. So that MDS does not end up | ||
1570 | * revoking the shared cap on every create/unlink | ||
1571 | * operation. | ||
1572 | */ | ||
1573 | want = CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_EXCL; | ||
1574 | retain |= want; | ||
1548 | } else { | 1575 | } else { |
1576 | |||
1549 | retain |= CEPH_CAP_ANY_SHARED; | 1577 | retain |= CEPH_CAP_ANY_SHARED; |
1550 | /* | 1578 | /* |
1551 | * keep RD only if we didn't have the file open RW, | 1579 | * keep RD only if we didn't have the file open RW, |
@@ -2309,6 +2337,9 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had) | |||
2309 | wake = 1; | 2337 | wake = 1; |
2310 | } | 2338 | } |
2311 | } | 2339 | } |
2340 | /* see comment in __ceph_remove_cap() */ | ||
2341 | if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) | ||
2342 | drop_inode_snap_realm(ci); | ||
2312 | } | 2343 | } |
2313 | spin_unlock(&ci->i_ceph_lock); | 2344 | spin_unlock(&ci->i_ceph_lock); |
2314 | 2345 | ||
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 83e9976f7189..e729b79812b4 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -281,6 +281,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx) | |||
281 | /* can we use the dcache? */ | 281 | /* can we use the dcache? */ |
282 | spin_lock(&ci->i_ceph_lock); | 282 | spin_lock(&ci->i_ceph_lock); |
283 | if ((ctx->pos == 2 || fi->dentry) && | 283 | if ((ctx->pos == 2 || fi->dentry) && |
284 | ceph_test_mount_opt(fsc, DCACHE) && | ||
284 | !ceph_test_mount_opt(fsc, NOASYNCREADDIR) && | 285 | !ceph_test_mount_opt(fsc, NOASYNCREADDIR) && |
285 | ceph_snap(inode) != CEPH_SNAPDIR && | 286 | ceph_snap(inode) != CEPH_SNAPDIR && |
286 | __ceph_dir_is_complete_ordered(ci) && | 287 | __ceph_dir_is_complete_ordered(ci) && |
@@ -336,16 +337,23 @@ more: | |||
336 | ceph_mdsc_put_request(req); | 337 | ceph_mdsc_put_request(req); |
337 | return err; | 338 | return err; |
338 | } | 339 | } |
339 | req->r_inode = inode; | ||
340 | ihold(inode); | ||
341 | req->r_dentry = dget(file->f_path.dentry); | ||
342 | /* hints to request -> mds selection code */ | 340 | /* hints to request -> mds selection code */ |
343 | req->r_direct_mode = USE_AUTH_MDS; | 341 | req->r_direct_mode = USE_AUTH_MDS; |
344 | req->r_direct_hash = ceph_frag_value(frag); | 342 | req->r_direct_hash = ceph_frag_value(frag); |
345 | req->r_direct_is_hash = true; | 343 | req->r_direct_is_hash = true; |
346 | req->r_path2 = kstrdup(fi->last_name, GFP_NOFS); | 344 | if (fi->last_name) { |
345 | req->r_path2 = kstrdup(fi->last_name, GFP_NOFS); | ||
346 | if (!req->r_path2) { | ||
347 | ceph_mdsc_put_request(req); | ||
348 | return -ENOMEM; | ||
349 | } | ||
350 | } | ||
347 | req->r_readdir_offset = fi->next_offset; | 351 | req->r_readdir_offset = fi->next_offset; |
348 | req->r_args.readdir.frag = cpu_to_le32(frag); | 352 | req->r_args.readdir.frag = cpu_to_le32(frag); |
353 | |||
354 | req->r_inode = inode; | ||
355 | ihold(inode); | ||
356 | req->r_dentry = dget(file->f_path.dentry); | ||
349 | err = ceph_mdsc_do_request(mdsc, NULL, req); | 357 | err = ceph_mdsc_do_request(mdsc, NULL, req); |
350 | if (err < 0) { | 358 | if (err < 0) { |
351 | ceph_mdsc_put_request(req); | 359 | ceph_mdsc_put_request(req); |
@@ -629,6 +637,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, | |||
629 | fsc->mount_options->snapdir_name, | 637 | fsc->mount_options->snapdir_name, |
630 | dentry->d_name.len) && | 638 | dentry->d_name.len) && |
631 | !is_root_ceph_dentry(dir, dentry) && | 639 | !is_root_ceph_dentry(dir, dentry) && |
640 | ceph_test_mount_opt(fsc, DCACHE) && | ||
632 | __ceph_dir_is_complete(ci) && | 641 | __ceph_dir_is_complete(ci) && |
633 | (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { | 642 | (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { |
634 | spin_unlock(&ci->i_ceph_lock); | 643 | spin_unlock(&ci->i_ceph_lock); |
@@ -755,10 +764,15 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry, | |||
755 | err = PTR_ERR(req); | 764 | err = PTR_ERR(req); |
756 | goto out; | 765 | goto out; |
757 | } | 766 | } |
758 | req->r_dentry = dget(dentry); | ||
759 | req->r_num_caps = 2; | ||
760 | req->r_path2 = kstrdup(dest, GFP_NOFS); | 767 | req->r_path2 = kstrdup(dest, GFP_NOFS); |
768 | if (!req->r_path2) { | ||
769 | err = -ENOMEM; | ||
770 | ceph_mdsc_put_request(req); | ||
771 | goto out; | ||
772 | } | ||
761 | req->r_locked_dir = dir; | 773 | req->r_locked_dir = dir; |
774 | req->r_dentry = dget(dentry); | ||
775 | req->r_num_caps = 2; | ||
762 | req->r_dentry_drop = CEPH_CAP_FILE_SHARED; | 776 | req->r_dentry_drop = CEPH_CAP_FILE_SHARED; |
763 | req->r_dentry_unless = CEPH_CAP_FILE_EXCL; | 777 | req->r_dentry_unless = CEPH_CAP_FILE_EXCL; |
764 | err = ceph_mdsc_do_request(mdsc, dir, req); | 778 | err = ceph_mdsc_do_request(mdsc, dir, req); |
@@ -933,16 +947,20 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
933 | struct ceph_fs_client *fsc = ceph_sb_to_client(old_dir->i_sb); | 947 | struct ceph_fs_client *fsc = ceph_sb_to_client(old_dir->i_sb); |
934 | struct ceph_mds_client *mdsc = fsc->mdsc; | 948 | struct ceph_mds_client *mdsc = fsc->mdsc; |
935 | struct ceph_mds_request *req; | 949 | struct ceph_mds_request *req; |
950 | int op = CEPH_MDS_OP_RENAME; | ||
936 | int err; | 951 | int err; |
937 | 952 | ||
938 | if (ceph_snap(old_dir) != ceph_snap(new_dir)) | 953 | if (ceph_snap(old_dir) != ceph_snap(new_dir)) |
939 | return -EXDEV; | 954 | return -EXDEV; |
940 | if (ceph_snap(old_dir) != CEPH_NOSNAP || | 955 | if (ceph_snap(old_dir) != CEPH_NOSNAP) { |
941 | ceph_snap(new_dir) != CEPH_NOSNAP) | 956 | if (old_dir == new_dir && ceph_snap(old_dir) == CEPH_SNAPDIR) |
942 | return -EROFS; | 957 | op = CEPH_MDS_OP_RENAMESNAP; |
958 | else | ||
959 | return -EROFS; | ||
960 | } | ||
943 | dout("rename dir %p dentry %p to dir %p dentry %p\n", | 961 | dout("rename dir %p dentry %p to dir %p dentry %p\n", |
944 | old_dir, old_dentry, new_dir, new_dentry); | 962 | old_dir, old_dentry, new_dir, new_dentry); |
945 | req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_RENAME, USE_AUTH_MDS); | 963 | req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); |
946 | if (IS_ERR(req)) | 964 | if (IS_ERR(req)) |
947 | return PTR_ERR(req); | 965 | return PTR_ERR(req); |
948 | ihold(old_dir); | 966 | ihold(old_dir); |
@@ -1240,11 +1258,12 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, | |||
1240 | dout("dir_fsync %p wait on tid %llu (until %llu)\n", | 1258 | dout("dir_fsync %p wait on tid %llu (until %llu)\n", |
1241 | inode, req->r_tid, last_tid); | 1259 | inode, req->r_tid, last_tid); |
1242 | if (req->r_timeout) { | 1260 | if (req->r_timeout) { |
1243 | ret = wait_for_completion_timeout( | 1261 | unsigned long time_left = wait_for_completion_timeout( |
1244 | &req->r_safe_completion, req->r_timeout); | 1262 | &req->r_safe_completion, |
1245 | if (ret > 0) | 1263 | req->r_timeout); |
1264 | if (time_left > 0) | ||
1246 | ret = 0; | 1265 | ret = 0; |
1247 | else if (ret == 0) | 1266 | else |
1248 | ret = -EIO; /* timed out */ | 1267 | ret = -EIO; /* timed out */ |
1249 | } else { | 1268 | } else { |
1250 | wait_for_completion(&req->r_safe_completion); | 1269 | wait_for_completion(&req->r_safe_completion); |
@@ -1372,6 +1391,7 @@ const struct inode_operations ceph_snapdir_iops = { | |||
1372 | .getattr = ceph_getattr, | 1391 | .getattr = ceph_getattr, |
1373 | .mkdir = ceph_mkdir, | 1392 | .mkdir = ceph_mkdir, |
1374 | .rmdir = ceph_unlink, | 1393 | .rmdir = ceph_unlink, |
1394 | .rename = ceph_rename, | ||
1375 | }; | 1395 | }; |
1376 | 1396 | ||
1377 | const struct dentry_operations ceph_dentry_ops = { | 1397 | const struct dentry_operations ceph_dentry_ops = { |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 71c073f38e54..0a2eb32ffe43 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -1021,6 +1021,33 @@ static void cleanup_cap_releases(struct ceph_mds_session *session) | |||
1021 | spin_unlock(&session->s_cap_lock); | 1021 | spin_unlock(&session->s_cap_lock); |
1022 | } | 1022 | } |
1023 | 1023 | ||
1024 | static void cleanup_session_requests(struct ceph_mds_client *mdsc, | ||
1025 | struct ceph_mds_session *session) | ||
1026 | { | ||
1027 | struct ceph_mds_request *req; | ||
1028 | struct rb_node *p; | ||
1029 | |||
1030 | dout("cleanup_session_requests mds%d\n", session->s_mds); | ||
1031 | mutex_lock(&mdsc->mutex); | ||
1032 | while (!list_empty(&session->s_unsafe)) { | ||
1033 | req = list_first_entry(&session->s_unsafe, | ||
1034 | struct ceph_mds_request, r_unsafe_item); | ||
1035 | list_del_init(&req->r_unsafe_item); | ||
1036 | pr_info(" dropping unsafe request %llu\n", req->r_tid); | ||
1037 | __unregister_request(mdsc, req); | ||
1038 | } | ||
1039 | /* zero r_attempts, so kick_requests() will re-send requests */ | ||
1040 | p = rb_first(&mdsc->request_tree); | ||
1041 | while (p) { | ||
1042 | req = rb_entry(p, struct ceph_mds_request, r_node); | ||
1043 | p = rb_next(p); | ||
1044 | if (req->r_session && | ||
1045 | req->r_session->s_mds == session->s_mds) | ||
1046 | req->r_attempts = 0; | ||
1047 | } | ||
1048 | mutex_unlock(&mdsc->mutex); | ||
1049 | } | ||
1050 | |||
1024 | /* | 1051 | /* |
1025 | * Helper to safely iterate over all caps associated with a session, with | 1052 | * Helper to safely iterate over all caps associated with a session, with |
1026 | * special care taken to handle a racing __ceph_remove_cap(). | 1053 | * special care taken to handle a racing __ceph_remove_cap(). |
@@ -1098,7 +1125,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
1098 | cap, ci, &ci->vfs_inode); | 1125 | cap, ci, &ci->vfs_inode); |
1099 | spin_lock(&ci->i_ceph_lock); | 1126 | spin_lock(&ci->i_ceph_lock); |
1100 | __ceph_remove_cap(cap, false); | 1127 | __ceph_remove_cap(cap, false); |
1101 | if (!__ceph_is_any_real_caps(ci)) { | 1128 | if (!ci->i_auth_cap) { |
1102 | struct ceph_mds_client *mdsc = | 1129 | struct ceph_mds_client *mdsc = |
1103 | ceph_sb_to_client(inode->i_sb)->mdsc; | 1130 | ceph_sb_to_client(inode->i_sb)->mdsc; |
1104 | 1131 | ||
@@ -1120,13 +1147,6 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
1120 | mdsc->num_cap_flushing--; | 1147 | mdsc->num_cap_flushing--; |
1121 | drop = 1; | 1148 | drop = 1; |
1122 | } | 1149 | } |
1123 | if (drop && ci->i_wrbuffer_ref) { | ||
1124 | pr_info(" dropping dirty data for %p %lld\n", | ||
1125 | inode, ceph_ino(inode)); | ||
1126 | ci->i_wrbuffer_ref = 0; | ||
1127 | ci->i_wrbuffer_ref_head = 0; | ||
1128 | drop++; | ||
1129 | } | ||
1130 | spin_unlock(&mdsc->cap_dirty_lock); | 1150 | spin_unlock(&mdsc->cap_dirty_lock); |
1131 | } | 1151 | } |
1132 | spin_unlock(&ci->i_ceph_lock); | 1152 | spin_unlock(&ci->i_ceph_lock); |
@@ -1853,7 +1873,7 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, | |||
1853 | */ | 1873 | */ |
1854 | static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, | 1874 | static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, |
1855 | struct ceph_mds_request *req, | 1875 | struct ceph_mds_request *req, |
1856 | int mds) | 1876 | int mds, bool drop_cap_releases) |
1857 | { | 1877 | { |
1858 | struct ceph_msg *msg; | 1878 | struct ceph_msg *msg; |
1859 | struct ceph_mds_request_head *head; | 1879 | struct ceph_mds_request_head *head; |
@@ -1937,6 +1957,12 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, | |||
1937 | releases += ceph_encode_inode_release(&p, | 1957 | releases += ceph_encode_inode_release(&p, |
1938 | req->r_old_dentry->d_inode, | 1958 | req->r_old_dentry->d_inode, |
1939 | mds, req->r_old_inode_drop, req->r_old_inode_unless, 0); | 1959 | mds, req->r_old_inode_drop, req->r_old_inode_unless, 0); |
1960 | |||
1961 | if (drop_cap_releases) { | ||
1962 | releases = 0; | ||
1963 | p = msg->front.iov_base + req->r_request_release_offset; | ||
1964 | } | ||
1965 | |||
1940 | head->num_releases = cpu_to_le16(releases); | 1966 | head->num_releases = cpu_to_le16(releases); |
1941 | 1967 | ||
1942 | /* time stamp */ | 1968 | /* time stamp */ |
@@ -1989,7 +2015,7 @@ static void complete_request(struct ceph_mds_client *mdsc, | |||
1989 | */ | 2015 | */ |
1990 | static int __prepare_send_request(struct ceph_mds_client *mdsc, | 2016 | static int __prepare_send_request(struct ceph_mds_client *mdsc, |
1991 | struct ceph_mds_request *req, | 2017 | struct ceph_mds_request *req, |
1992 | int mds) | 2018 | int mds, bool drop_cap_releases) |
1993 | { | 2019 | { |
1994 | struct ceph_mds_request_head *rhead; | 2020 | struct ceph_mds_request_head *rhead; |
1995 | struct ceph_msg *msg; | 2021 | struct ceph_msg *msg; |
@@ -2048,7 +2074,7 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc, | |||
2048 | ceph_msg_put(req->r_request); | 2074 | ceph_msg_put(req->r_request); |
2049 | req->r_request = NULL; | 2075 | req->r_request = NULL; |
2050 | } | 2076 | } |
2051 | msg = create_request_message(mdsc, req, mds); | 2077 | msg = create_request_message(mdsc, req, mds, drop_cap_releases); |
2052 | if (IS_ERR(msg)) { | 2078 | if (IS_ERR(msg)) { |
2053 | req->r_err = PTR_ERR(msg); | 2079 | req->r_err = PTR_ERR(msg); |
2054 | complete_request(mdsc, req); | 2080 | complete_request(mdsc, req); |
@@ -2132,7 +2158,7 @@ static int __do_request(struct ceph_mds_client *mdsc, | |||
2132 | if (req->r_request_started == 0) /* note request start time */ | 2158 | if (req->r_request_started == 0) /* note request start time */ |
2133 | req->r_request_started = jiffies; | 2159 | req->r_request_started = jiffies; |
2134 | 2160 | ||
2135 | err = __prepare_send_request(mdsc, req, mds); | 2161 | err = __prepare_send_request(mdsc, req, mds, false); |
2136 | if (!err) { | 2162 | if (!err) { |
2137 | ceph_msg_get(req->r_request); | 2163 | ceph_msg_get(req->r_request); |
2138 | ceph_con_send(&session->s_con, req->r_request); | 2164 | ceph_con_send(&session->s_con, req->r_request); |
@@ -2590,6 +2616,7 @@ static void handle_session(struct ceph_mds_session *session, | |||
2590 | case CEPH_SESSION_CLOSE: | 2616 | case CEPH_SESSION_CLOSE: |
2591 | if (session->s_state == CEPH_MDS_SESSION_RECONNECTING) | 2617 | if (session->s_state == CEPH_MDS_SESSION_RECONNECTING) |
2592 | pr_info("mds%d reconnect denied\n", session->s_mds); | 2618 | pr_info("mds%d reconnect denied\n", session->s_mds); |
2619 | cleanup_session_requests(mdsc, session); | ||
2593 | remove_session_caps(session); | 2620 | remove_session_caps(session); |
2594 | wake = 2; /* for good measure */ | 2621 | wake = 2; /* for good measure */ |
2595 | wake_up_all(&mdsc->session_close_wq); | 2622 | wake_up_all(&mdsc->session_close_wq); |
@@ -2658,7 +2685,7 @@ static void replay_unsafe_requests(struct ceph_mds_client *mdsc, | |||
2658 | 2685 | ||
2659 | mutex_lock(&mdsc->mutex); | 2686 | mutex_lock(&mdsc->mutex); |
2660 | list_for_each_entry_safe(req, nreq, &session->s_unsafe, r_unsafe_item) { | 2687 | list_for_each_entry_safe(req, nreq, &session->s_unsafe, r_unsafe_item) { |
2661 | err = __prepare_send_request(mdsc, req, session->s_mds); | 2688 | err = __prepare_send_request(mdsc, req, session->s_mds, true); |
2662 | if (!err) { | 2689 | if (!err) { |
2663 | ceph_msg_get(req->r_request); | 2690 | ceph_msg_get(req->r_request); |
2664 | ceph_con_send(&session->s_con, req->r_request); | 2691 | ceph_con_send(&session->s_con, req->r_request); |
@@ -2679,7 +2706,8 @@ static void replay_unsafe_requests(struct ceph_mds_client *mdsc, | |||
2679 | continue; /* only old requests */ | 2706 | continue; /* only old requests */ |
2680 | if (req->r_session && | 2707 | if (req->r_session && |
2681 | req->r_session->s_mds == session->s_mds) { | 2708 | req->r_session->s_mds == session->s_mds) { |
2682 | err = __prepare_send_request(mdsc, req, session->s_mds); | 2709 | err = __prepare_send_request(mdsc, req, |
2710 | session->s_mds, true); | ||
2683 | if (!err) { | 2711 | if (!err) { |
2684 | ceph_msg_get(req->r_request); | 2712 | ceph_msg_get(req->r_request); |
2685 | ceph_con_send(&session->s_con, req->r_request); | 2713 | ceph_con_send(&session->s_con, req->r_request); |
@@ -2864,7 +2892,8 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, | |||
2864 | spin_unlock(&session->s_cap_lock); | 2892 | spin_unlock(&session->s_cap_lock); |
2865 | 2893 | ||
2866 | /* trim unused caps to reduce MDS's cache rejoin time */ | 2894 | /* trim unused caps to reduce MDS's cache rejoin time */ |
2867 | shrink_dcache_parent(mdsc->fsc->sb->s_root); | 2895 | if (mdsc->fsc->sb->s_root) |
2896 | shrink_dcache_parent(mdsc->fsc->sb->s_root); | ||
2868 | 2897 | ||
2869 | ceph_con_close(&session->s_con); | 2898 | ceph_con_close(&session->s_con); |
2870 | ceph_con_open(&session->s_con, | 2899 | ceph_con_open(&session->s_con, |
@@ -3133,7 +3162,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, | |||
3133 | di->lease_renew_from && | 3162 | di->lease_renew_from && |
3134 | di->lease_renew_after == 0) { | 3163 | di->lease_renew_after == 0) { |
3135 | unsigned long duration = | 3164 | unsigned long duration = |
3136 | le32_to_cpu(h->duration_ms) * HZ / 1000; | 3165 | msecs_to_jiffies(le32_to_cpu(h->duration_ms)); |
3137 | 3166 | ||
3138 | di->lease_seq = seq; | 3167 | di->lease_seq = seq; |
3139 | dentry->d_time = di->lease_renew_from + duration; | 3168 | dentry->d_time = di->lease_renew_from + duration; |
diff --git a/fs/ceph/strings.c b/fs/ceph/strings.c index 51cc23e48111..89e6bc321df3 100644 --- a/fs/ceph/strings.c +++ b/fs/ceph/strings.c | |||
@@ -75,6 +75,7 @@ const char *ceph_mds_op_name(int op) | |||
75 | case CEPH_MDS_OP_LSSNAP: return "lssnap"; | 75 | case CEPH_MDS_OP_LSSNAP: return "lssnap"; |
76 | case CEPH_MDS_OP_MKSNAP: return "mksnap"; | 76 | case CEPH_MDS_OP_MKSNAP: return "mksnap"; |
77 | case CEPH_MDS_OP_RMSNAP: return "rmsnap"; | 77 | case CEPH_MDS_OP_RMSNAP: return "rmsnap"; |
78 | case CEPH_MDS_OP_RENAMESNAP: return "renamesnap"; | ||
78 | case CEPH_MDS_OP_SETFILELOCK: return "setfilelock"; | 79 | case CEPH_MDS_OP_SETFILELOCK: return "setfilelock"; |
79 | case CEPH_MDS_OP_GETFILELOCK: return "getfilelock"; | 80 | case CEPH_MDS_OP_GETFILELOCK: return "getfilelock"; |
80 | } | 81 | } |
diff --git a/fs/ceph/super.c b/fs/ceph/super.c index a63997b8bcff..e463ebd69a9c 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c | |||
@@ -345,6 +345,11 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt, | |||
345 | fsopt->rsize = CEPH_RSIZE_DEFAULT; | 345 | fsopt->rsize = CEPH_RSIZE_DEFAULT; |
346 | fsopt->rasize = CEPH_RASIZE_DEFAULT; | 346 | fsopt->rasize = CEPH_RASIZE_DEFAULT; |
347 | fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL); | 347 | fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL); |
348 | if (!fsopt->snapdir_name) { | ||
349 | err = -ENOMEM; | ||
350 | goto out; | ||
351 | } | ||
352 | |||
348 | fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT; | 353 | fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT; |
349 | fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT; | 354 | fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT; |
350 | fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT; | 355 | fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT; |
@@ -406,31 +411,20 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) | |||
406 | { | 411 | { |
407 | struct ceph_fs_client *fsc = ceph_sb_to_client(root->d_sb); | 412 | struct ceph_fs_client *fsc = ceph_sb_to_client(root->d_sb); |
408 | struct ceph_mount_options *fsopt = fsc->mount_options; | 413 | struct ceph_mount_options *fsopt = fsc->mount_options; |
409 | struct ceph_options *opt = fsc->client->options; | 414 | size_t pos; |
410 | 415 | int ret; | |
411 | if (opt->flags & CEPH_OPT_FSID) | 416 | |
412 | seq_printf(m, ",fsid=%pU", &opt->fsid); | 417 | /* a comma between MNT/MS and client options */ |
413 | if (opt->flags & CEPH_OPT_NOSHARE) | 418 | seq_putc(m, ','); |
414 | seq_puts(m, ",noshare"); | 419 | pos = m->count; |
415 | if (opt->flags & CEPH_OPT_NOCRC) | 420 | |
416 | seq_puts(m, ",nocrc"); | 421 | ret = ceph_print_client_options(m, fsc->client); |
417 | if (opt->flags & CEPH_OPT_NOMSGAUTH) | 422 | if (ret) |
418 | seq_puts(m, ",nocephx_require_signatures"); | 423 | return ret; |
419 | if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0) | 424 | |
420 | seq_puts(m, ",notcp_nodelay"); | 425 | /* retract our comma if no client options */ |
421 | 426 | if (m->count == pos) | |
422 | if (opt->name) | 427 | m->count--; |
423 | seq_printf(m, ",name=%s", opt->name); | ||
424 | if (opt->key) | ||
425 | seq_puts(m, ",secret=<hidden>"); | ||
426 | |||
427 | if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) | ||
428 | seq_printf(m, ",mount_timeout=%d", opt->mount_timeout); | ||
429 | if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) | ||
430 | seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl); | ||
431 | if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) | ||
432 | seq_printf(m, ",osdkeepalivetimeout=%d", | ||
433 | opt->osd_keepalive_timeout); | ||
434 | 428 | ||
435 | if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT) | 429 | if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT) |
436 | seq_puts(m, ",dirstat"); | 430 | seq_puts(m, ",dirstat"); |
@@ -438,14 +432,10 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) | |||
438 | seq_puts(m, ",norbytes"); | 432 | seq_puts(m, ",norbytes"); |
439 | if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR) | 433 | if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR) |
440 | seq_puts(m, ",noasyncreaddir"); | 434 | seq_puts(m, ",noasyncreaddir"); |
441 | if (fsopt->flags & CEPH_MOUNT_OPT_DCACHE) | 435 | if ((fsopt->flags & CEPH_MOUNT_OPT_DCACHE) == 0) |
442 | seq_puts(m, ",dcache"); | ||
443 | else | ||
444 | seq_puts(m, ",nodcache"); | 436 | seq_puts(m, ",nodcache"); |
445 | if (fsopt->flags & CEPH_MOUNT_OPT_FSCACHE) | 437 | if (fsopt->flags & CEPH_MOUNT_OPT_FSCACHE) |
446 | seq_puts(m, ",fsc"); | 438 | seq_puts(m, ",fsc"); |
447 | else | ||
448 | seq_puts(m, ",nofsc"); | ||
449 | 439 | ||
450 | #ifdef CONFIG_CEPH_FS_POSIX_ACL | 440 | #ifdef CONFIG_CEPH_FS_POSIX_ACL |
451 | if (fsopt->sb_flags & MS_POSIXACL) | 441 | if (fsopt->sb_flags & MS_POSIXACL) |
@@ -477,6 +467,7 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) | |||
477 | seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes); | 467 | seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes); |
478 | if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT)) | 468 | if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT)) |
479 | seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name); | 469 | seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name); |
470 | |||
480 | return 0; | 471 | return 0; |
481 | } | 472 | } |
482 | 473 | ||
@@ -730,6 +721,11 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, | |||
730 | if (IS_ERR(req)) | 721 | if (IS_ERR(req)) |
731 | return ERR_CAST(req); | 722 | return ERR_CAST(req); |
732 | req->r_path1 = kstrdup(path, GFP_NOFS); | 723 | req->r_path1 = kstrdup(path, GFP_NOFS); |
724 | if (!req->r_path1) { | ||
725 | root = ERR_PTR(-ENOMEM); | ||
726 | goto out; | ||
727 | } | ||
728 | |||
733 | req->r_ino1.ino = CEPH_INO_ROOT; | 729 | req->r_ino1.ino = CEPH_INO_ROOT; |
734 | req->r_ino1.snap = CEPH_NOSNAP; | 730 | req->r_ino1.snap = CEPH_NOSNAP; |
735 | req->r_started = started; | 731 | req->r_started = started; |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 04c8124ed30e..fa20e1318939 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -36,7 +36,8 @@ | |||
36 | #define CEPH_MOUNT_OPT_DCACHE (1<<9) /* use dcache for readdir etc */ | 36 | #define CEPH_MOUNT_OPT_DCACHE (1<<9) /* use dcache for readdir etc */ |
37 | #define CEPH_MOUNT_OPT_FSCACHE (1<<10) /* use fscache */ | 37 | #define CEPH_MOUNT_OPT_FSCACHE (1<<10) /* use fscache */ |
38 | 38 | ||
39 | #define CEPH_MOUNT_OPT_DEFAULT (CEPH_MOUNT_OPT_RBYTES) | 39 | #define CEPH_MOUNT_OPT_DEFAULT (CEPH_MOUNT_OPT_RBYTES | \ |
40 | CEPH_MOUNT_OPT_DCACHE) | ||
40 | 41 | ||
41 | #define ceph_set_mount_opt(fsc, opt) \ | 42 | #define ceph_set_mount_opt(fsc, opt) \ |
42 | (fsc)->mount_options->flags |= CEPH_MOUNT_OPT_##opt; | 43 | (fsc)->mount_options->flags |= CEPH_MOUNT_OPT_##opt; |
@@ -881,7 +882,6 @@ extern int ceph_mmap(struct file *file, struct vm_area_struct *vma); | |||
881 | 882 | ||
882 | /* file.c */ | 883 | /* file.c */ |
883 | extern const struct file_operations ceph_file_fops; | 884 | extern const struct file_operations ceph_file_fops; |
884 | extern const struct address_space_operations ceph_aops; | ||
885 | 885 | ||
886 | extern int ceph_open(struct inode *inode, struct file *file); | 886 | extern int ceph_open(struct inode *inode, struct file *file); |
887 | extern int ceph_atomic_open(struct inode *dir, struct dentry *dentry, | 887 | extern int ceph_atomic_open(struct inode *dir, struct dentry *dentry, |
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 5a492caf34cb..5c4c9c256931 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c | |||
@@ -877,16 +877,23 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name, | |||
877 | err = PTR_ERR(req); | 877 | err = PTR_ERR(req); |
878 | goto out; | 878 | goto out; |
879 | } | 879 | } |
880 | req->r_inode = inode; | 880 | |
881 | ihold(inode); | ||
882 | req->r_inode_drop = CEPH_CAP_XATTR_SHARED; | ||
883 | req->r_num_caps = 1; | ||
884 | req->r_args.setxattr.flags = cpu_to_le32(flags); | 881 | req->r_args.setxattr.flags = cpu_to_le32(flags); |
885 | req->r_path2 = kstrdup(name, GFP_NOFS); | 882 | req->r_path2 = kstrdup(name, GFP_NOFS); |
883 | if (!req->r_path2) { | ||
884 | ceph_mdsc_put_request(req); | ||
885 | err = -ENOMEM; | ||
886 | goto out; | ||
887 | } | ||
886 | 888 | ||
887 | req->r_pagelist = pagelist; | 889 | req->r_pagelist = pagelist; |
888 | pagelist = NULL; | 890 | pagelist = NULL; |
889 | 891 | ||
892 | req->r_inode = inode; | ||
893 | ihold(inode); | ||
894 | req->r_num_caps = 1; | ||
895 | req->r_inode_drop = CEPH_CAP_XATTR_SHARED; | ||
896 | |||
890 | dout("xattr.ver (before): %lld\n", ci->i_xattrs.version); | 897 | dout("xattr.ver (before): %lld\n", ci->i_xattrs.version); |
891 | err = ceph_mdsc_do_request(mdsc, NULL, req); | 898 | err = ceph_mdsc_do_request(mdsc, NULL, req); |
892 | ceph_mdsc_put_request(req); | 899 | ceph_mdsc_put_request(req); |
@@ -1019,12 +1026,14 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name) | |||
1019 | USE_AUTH_MDS); | 1026 | USE_AUTH_MDS); |
1020 | if (IS_ERR(req)) | 1027 | if (IS_ERR(req)) |
1021 | return PTR_ERR(req); | 1028 | return PTR_ERR(req); |
1029 | req->r_path2 = kstrdup(name, GFP_NOFS); | ||
1030 | if (!req->r_path2) | ||
1031 | return -ENOMEM; | ||
1032 | |||
1022 | req->r_inode = inode; | 1033 | req->r_inode = inode; |
1023 | ihold(inode); | 1034 | ihold(inode); |
1024 | req->r_inode_drop = CEPH_CAP_XATTR_SHARED; | ||
1025 | req->r_num_caps = 1; | 1035 | req->r_num_caps = 1; |
1026 | req->r_path2 = kstrdup(name, GFP_NOFS); | 1036 | req->r_inode_drop = CEPH_CAP_XATTR_SHARED; |
1027 | |||
1028 | err = ceph_mdsc_do_request(mdsc, NULL, req); | 1037 | err = ceph_mdsc_do_request(mdsc, NULL, req); |
1029 | ceph_mdsc_put_request(req); | 1038 | ceph_mdsc_put_request(req); |
1030 | return err; | 1039 | return err; |