diff options
Diffstat (limited to 'fs/ceph/mds_client.c')
-rw-r--r-- | fs/ceph/mds_client.c | 97 |
1 files changed, 70 insertions, 27 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index f4f050a69a48..2b4d093d0563 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/fs.h> | 3 | #include <linux/fs.h> |
4 | #include <linux/wait.h> | 4 | #include <linux/wait.h> |
5 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
6 | #include <linux/gfp.h> | ||
6 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
7 | #include <linux/debugfs.h> | 8 | #include <linux/debugfs.h> |
8 | #include <linux/seq_file.h> | 9 | #include <linux/seq_file.h> |
@@ -165,21 +166,18 @@ static int parse_reply_info_dir(void **p, void *end, | |||
165 | if (num == 0) | 166 | if (num == 0) |
166 | goto done; | 167 | goto done; |
167 | 168 | ||
168 | /* alloc large array */ | 169 | BUG_ON(!info->dir_in); |
169 | info->dir_nr = num; | ||
170 | info->dir_in = kcalloc(num, sizeof(*info->dir_in) + | ||
171 | sizeof(*info->dir_dname) + | ||
172 | sizeof(*info->dir_dname_len) + | ||
173 | sizeof(*info->dir_dlease), | ||
174 | GFP_NOFS); | ||
175 | if (info->dir_in == NULL) { | ||
176 | err = -ENOMEM; | ||
177 | goto out_bad; | ||
178 | } | ||
179 | info->dir_dname = (void *)(info->dir_in + num); | 170 | info->dir_dname = (void *)(info->dir_in + num); |
180 | info->dir_dname_len = (void *)(info->dir_dname + num); | 171 | info->dir_dname_len = (void *)(info->dir_dname + num); |
181 | info->dir_dlease = (void *)(info->dir_dname_len + num); | 172 | info->dir_dlease = (void *)(info->dir_dname_len + num); |
173 | if ((unsigned long)(info->dir_dlease + num) > | ||
174 | (unsigned long)info->dir_in + info->dir_buf_size) { | ||
175 | pr_err("dir contents are larger than expected\n"); | ||
176 | WARN_ON(1); | ||
177 | goto bad; | ||
178 | } | ||
182 | 179 | ||
180 | info->dir_nr = num; | ||
183 | while (num) { | 181 | while (num) { |
184 | /* dentry */ | 182 | /* dentry */ |
185 | ceph_decode_need(p, end, sizeof(u32)*2, bad); | 183 | ceph_decode_need(p, end, sizeof(u32)*2, bad); |
@@ -327,7 +325,9 @@ out_bad: | |||
327 | 325 | ||
328 | static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info) | 326 | static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info) |
329 | { | 327 | { |
330 | kfree(info->dir_in); | 328 | if (!info->dir_in) |
329 | return; | ||
330 | free_pages((unsigned long)info->dir_in, get_order(info->dir_buf_size)); | ||
331 | } | 331 | } |
332 | 332 | ||
333 | 333 | ||
@@ -512,12 +512,11 @@ void ceph_mdsc_release_request(struct kref *kref) | |||
512 | struct ceph_mds_request *req = container_of(kref, | 512 | struct ceph_mds_request *req = container_of(kref, |
513 | struct ceph_mds_request, | 513 | struct ceph_mds_request, |
514 | r_kref); | 514 | r_kref); |
515 | destroy_reply_info(&req->r_reply_info); | ||
515 | if (req->r_request) | 516 | if (req->r_request) |
516 | ceph_msg_put(req->r_request); | 517 | ceph_msg_put(req->r_request); |
517 | if (req->r_reply) { | 518 | if (req->r_reply) |
518 | ceph_msg_put(req->r_reply); | 519 | ceph_msg_put(req->r_reply); |
519 | destroy_reply_info(&req->r_reply_info); | ||
520 | } | ||
521 | if (req->r_inode) { | 520 | if (req->r_inode) { |
522 | ceph_put_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); | 521 | ceph_put_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); |
523 | iput(req->r_inode); | 522 | iput(req->r_inode); |
@@ -528,7 +527,9 @@ void ceph_mdsc_release_request(struct kref *kref) | |||
528 | iput(req->r_target_inode); | 527 | iput(req->r_target_inode); |
529 | if (req->r_dentry) | 528 | if (req->r_dentry) |
530 | dput(req->r_dentry); | 529 | dput(req->r_dentry); |
531 | if (req->r_old_dentry) { | 530 | if (req->r_old_dentry) |
531 | dput(req->r_old_dentry); | ||
532 | if (req->r_old_dentry_dir) { | ||
532 | /* | 533 | /* |
533 | * track (and drop pins for) r_old_dentry_dir | 534 | * track (and drop pins for) r_old_dentry_dir |
534 | * separately, since r_old_dentry's d_parent may have | 535 | * separately, since r_old_dentry's d_parent may have |
@@ -537,7 +538,6 @@ void ceph_mdsc_release_request(struct kref *kref) | |||
537 | */ | 538 | */ |
538 | ceph_put_cap_refs(ceph_inode(req->r_old_dentry_dir), | 539 | ceph_put_cap_refs(ceph_inode(req->r_old_dentry_dir), |
539 | CEPH_CAP_PIN); | 540 | CEPH_CAP_PIN); |
540 | dput(req->r_old_dentry); | ||
541 | iput(req->r_old_dentry_dir); | 541 | iput(req->r_old_dentry_dir); |
542 | } | 542 | } |
543 | kfree(req->r_path1); | 543 | kfree(req->r_path1); |
@@ -1311,6 +1311,9 @@ static int trim_caps(struct ceph_mds_client *mdsc, | |||
1311 | trim_caps - session->s_trim_caps); | 1311 | trim_caps - session->s_trim_caps); |
1312 | session->s_trim_caps = 0; | 1312 | session->s_trim_caps = 0; |
1313 | } | 1313 | } |
1314 | |||
1315 | ceph_add_cap_releases(mdsc, session); | ||
1316 | ceph_send_cap_releases(mdsc, session); | ||
1314 | return 0; | 1317 | return 0; |
1315 | } | 1318 | } |
1316 | 1319 | ||
@@ -1461,15 +1464,18 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc, | |||
1461 | 1464 | ||
1462 | dout("discard_cap_releases mds%d\n", session->s_mds); | 1465 | dout("discard_cap_releases mds%d\n", session->s_mds); |
1463 | 1466 | ||
1464 | /* zero out the in-progress message */ | 1467 | if (!list_empty(&session->s_cap_releases)) { |
1465 | msg = list_first_entry(&session->s_cap_releases, | 1468 | /* zero out the in-progress message */ |
1466 | struct ceph_msg, list_head); | 1469 | msg = list_first_entry(&session->s_cap_releases, |
1467 | head = msg->front.iov_base; | 1470 | struct ceph_msg, list_head); |
1468 | num = le32_to_cpu(head->num); | 1471 | head = msg->front.iov_base; |
1469 | dout("discard_cap_releases mds%d %p %u\n", session->s_mds, msg, num); | 1472 | num = le32_to_cpu(head->num); |
1470 | head->num = cpu_to_le32(0); | 1473 | dout("discard_cap_releases mds%d %p %u\n", |
1471 | msg->front.iov_len = sizeof(*head); | 1474 | session->s_mds, msg, num); |
1472 | session->s_num_cap_releases += num; | 1475 | head->num = cpu_to_le32(0); |
1476 | msg->front.iov_len = sizeof(*head); | ||
1477 | session->s_num_cap_releases += num; | ||
1478 | } | ||
1473 | 1479 | ||
1474 | /* requeue completed messages */ | 1480 | /* requeue completed messages */ |
1475 | while (!list_empty(&session->s_cap_releases_done)) { | 1481 | while (!list_empty(&session->s_cap_releases_done)) { |
@@ -1492,6 +1498,43 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc, | |||
1492 | * requests | 1498 | * requests |
1493 | */ | 1499 | */ |
1494 | 1500 | ||
1501 | int ceph_alloc_readdir_reply_buffer(struct ceph_mds_request *req, | ||
1502 | struct inode *dir) | ||
1503 | { | ||
1504 | struct ceph_inode_info *ci = ceph_inode(dir); | ||
1505 | struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info; | ||
1506 | struct ceph_mount_options *opt = req->r_mdsc->fsc->mount_options; | ||
1507 | size_t size = sizeof(*rinfo->dir_in) + sizeof(*rinfo->dir_dname_len) + | ||
1508 | sizeof(*rinfo->dir_dname) + sizeof(*rinfo->dir_dlease); | ||
1509 | int order, num_entries; | ||
1510 | |||
1511 | spin_lock(&ci->i_ceph_lock); | ||
1512 | num_entries = ci->i_files + ci->i_subdirs; | ||
1513 | spin_unlock(&ci->i_ceph_lock); | ||
1514 | num_entries = max(num_entries, 1); | ||
1515 | num_entries = min(num_entries, opt->max_readdir); | ||
1516 | |||
1517 | order = get_order(size * num_entries); | ||
1518 | while (order >= 0) { | ||
1519 | rinfo->dir_in = (void*)__get_free_pages(GFP_NOFS | __GFP_NOWARN, | ||
1520 | order); | ||
1521 | if (rinfo->dir_in) | ||
1522 | break; | ||
1523 | order--; | ||
1524 | } | ||
1525 | if (!rinfo->dir_in) | ||
1526 | return -ENOMEM; | ||
1527 | |||
1528 | num_entries = (PAGE_SIZE << order) / size; | ||
1529 | num_entries = min(num_entries, opt->max_readdir); | ||
1530 | |||
1531 | rinfo->dir_buf_size = PAGE_SIZE << order; | ||
1532 | req->r_num_caps = num_entries + 1; | ||
1533 | req->r_args.readdir.max_entries = cpu_to_le32(num_entries); | ||
1534 | req->r_args.readdir.max_bytes = cpu_to_le32(opt->max_readdir_bytes); | ||
1535 | return 0; | ||
1536 | } | ||
1537 | |||
1495 | /* | 1538 | /* |
1496 | * Create an mds request. | 1539 | * Create an mds request. |
1497 | */ | 1540 | */ |
@@ -2053,7 +2096,7 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc, | |||
2053 | ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); | 2096 | ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN); |
2054 | if (req->r_locked_dir) | 2097 | if (req->r_locked_dir) |
2055 | ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN); | 2098 | ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN); |
2056 | if (req->r_old_dentry) | 2099 | if (req->r_old_dentry_dir) |
2057 | ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir), | 2100 | ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir), |
2058 | CEPH_CAP_PIN); | 2101 | CEPH_CAP_PIN); |
2059 | 2102 | ||