aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph/mds_client.c
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2014-03-29 01:41:15 -0400
committerSage Weil <sage@inktank.com>2014-04-05 00:08:22 -0400
commit54008399dc0ce511a07b87f1af3d1f5c791982a4 (patch)
tree6482779b43a6860debd35d11bc9a717efb262e20 /fs/ceph/mds_client.c
parent18cb95af2d7c69aa136ab13f02dd55188c120e75 (diff)
ceph: preallocate buffer for readdir reply
Preallocate buffer for readdir reply. Limit number of entries in readdir reply according to the buffer size. Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Diffstat (limited to 'fs/ceph/mds_client.c')
-rw-r--r--fs/ceph/mds_client.c66
1 files changed, 51 insertions, 15 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 77640ada487a..19fbfc496137 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
328static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info) 326static 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);
@@ -1496,6 +1495,43 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc,
1496 * requests 1495 * requests
1497 */ 1496 */
1498 1497
1498int ceph_alloc_readdir_reply_buffer(struct ceph_mds_request *req,
1499 struct inode *dir)
1500{
1501 struct ceph_inode_info *ci = ceph_inode(dir);
1502 struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
1503 struct ceph_mount_options *opt = req->r_mdsc->fsc->mount_options;
1504 size_t size = sizeof(*rinfo->dir_in) + sizeof(*rinfo->dir_dname_len) +
1505 sizeof(*rinfo->dir_dname) + sizeof(*rinfo->dir_dlease);
1506 int order, num_entries;
1507
1508 spin_lock(&ci->i_ceph_lock);
1509 num_entries = ci->i_files + ci->i_subdirs;
1510 spin_unlock(&ci->i_ceph_lock);
1511 num_entries = max(num_entries, 1);
1512 num_entries = min(num_entries, opt->max_readdir);
1513
1514 order = get_order(size * num_entries);
1515 while (order >= 0) {
1516 rinfo->dir_in = (void*)__get_free_pages(GFP_NOFS | __GFP_NOWARN,
1517 order);
1518 if (rinfo->dir_in)
1519 break;
1520 order--;
1521 }
1522 if (!rinfo->dir_in)
1523 return -ENOMEM;
1524
1525 num_entries = (PAGE_SIZE << order) / size;
1526 num_entries = min(num_entries, opt->max_readdir);
1527
1528 rinfo->dir_buf_size = PAGE_SIZE << order;
1529 req->r_num_caps = num_entries + 1;
1530 req->r_args.readdir.max_entries = cpu_to_le32(num_entries);
1531 req->r_args.readdir.max_bytes = cpu_to_le32(opt->max_readdir_bytes);
1532 return 0;
1533}
1534
1499/* 1535/*
1500 * Create an mds request. 1536 * Create an mds request.
1501 */ 1537 */