Re: [PATCH] ceph: optimize memory usage

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> Sent: Tuesday, March 06, 2018 at 4:34 PM
> From: "Yan, Zheng" <ukernel@xxxxxxxxx>
> To: "Chengguang Xu" <cgxu519@xxxxxxx>
> Cc: "Zheng Yan" <zyan@xxxxxxxxxx>, "Ilya Dryomov" <idryomov@xxxxxxxxx>, ceph-devel <ceph-devel@xxxxxxxxxxxxxxx>
> Subject: Re: [PATCH] ceph: optimize memory usage
>
> On Mon, Mar 5, 2018 at 8:17 PM, Chengguang Xu <cgxu519@xxxxxxx> wrote:
> > In current code, regular file and directory use same struct
> > ceph_file_info to store fs specific data so the struct has to
> > include some fields which are only used for directory
> > (e.g., readdir related info), when having plenty of regular files,
> > it will lead to memory waste.
> >
> > This patch introduces dedicated readdir_info cache to separate readdir
> > related things from struct ceph_file_info, so that regular file could
> > not include those unused fields anymore. Also, chagned to manipulate
> > fscache only when reuglar file successfully acquired ceph_file_info.
> >
> > Signed-off-by: Chengguang Xu <cgxu519@xxxxxxx>
> > ---
> >  fs/ceph/dir.c                | 158 +++++++++++++++++++++++--------------------
> >  fs/ceph/file.c               |  88 ++++++++++++++++--------
> >  fs/ceph/super.c              |  14 +++-
> >  fs/ceph/super.h              |  19 ++++--
> >  include/linux/ceph/libceph.h |   1 +
> >  5 files changed, 170 insertions(+), 110 deletions(-)
> >
> > diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
> > index 0c43468..84bc75a 100644
> > --- a/fs/ceph/dir.c
> > +++ b/fs/ceph/dir.c
> > @@ -105,15 +105,17 @@ static int fpos_cmp(loff_t l, loff_t r)
> >  static int note_last_dentry(struct ceph_file_info *fi, const char *name,
> >                             int len, unsigned next_offset)
> >  {
> > +       struct ceph_readdir_info *ri = fi->readdir_info;
> >         char *buf = kmalloc(len+1, GFP_KERNEL);
> >         if (!buf)
> >                 return -ENOMEM;
> > -       kfree(fi->last_name);
> > -       fi->last_name = buf;
> > -       memcpy(fi->last_name, name, len);
> > -       fi->last_name[len] = 0;
> > -       fi->next_offset = next_offset;
> > -       dout("note_last_dentry '%s'\n", fi->last_name);
> > +
> > +       kfree(ri->last_name);
> > +       ri->last_name = buf;
> > +       memcpy(ri->last_name, name, len);
> > +       ri->last_name[len] = 0;
> > +       ri->next_offset = next_offset;
> > +       dout("note_last_dentry '%s'\n", ri->last_name);
> >         return 0;
> >  }
> >
> > @@ -176,6 +178,7 @@ static int __dcache_readdir(struct file *file,  struct dir_context *ctx,
> >                             int shared_gen)
> >  {
> >         struct ceph_file_info *fi = file->private_data;
> > +       struct ceph_readdir_info *ri = fi->readdir_info;
> >         struct dentry *parent = file->f_path.dentry;
> >         struct inode *dir = d_inode(parent);
> >         struct dentry *dentry, *last = NULL;
> > @@ -279,9 +282,9 @@ static int __dcache_readdir(struct file *file,  struct dir_context *ctx,
> >                         err = ret;
> >                 dput(last);
> >                 /* last_name no longer match cache index */
> > -               if (fi->readdir_cache_idx >= 0) {
> > -                       fi->readdir_cache_idx = -1;
> > -                       fi->dir_release_count = 0;
> > +               if (ri->readdir_cache_idx >= 0) {
> > +                       ri->readdir_cache_idx = -1;
> > +                       ri->dir_release_count = 0;
> >                 }
> >         }
> >         return err;
> > @@ -289,17 +292,20 @@ static int __dcache_readdir(struct file *file,  struct dir_context *ctx,
> >
> >  static bool need_send_readdir(struct ceph_file_info *fi, loff_t pos)
> >  {
> > -       if (!fi->last_readdir)
> > +       struct ceph_readdir_info *ri = fi->readdir_info;
> > +
> > +       if (!ri->last_readdir)
> >                 return true;
> >         if (is_hash_order(pos))
> > -               return !ceph_frag_contains_value(fi->frag, fpos_hash(pos));
> > +               return !ceph_frag_contains_value(ri->frag, fpos_hash(pos));
> >         else
> > -               return fi->frag != fpos_frag(pos);
> > +               return ri->frag != fpos_frag(pos);
> >  }
> >
> >  static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >  {
> >         struct ceph_file_info *fi = file->private_data;
> > +       struct ceph_readdir_info *ri = fi->readdir_info;
> >         struct inode *inode = file_inode(file);
> >         struct ceph_inode_info *ci = ceph_inode(inode);
> >         struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
> > @@ -357,9 +363,9 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >                         CEPH_MDS_OP_LSSNAP : CEPH_MDS_OP_READDIR;
> >
> >                 /* discard old result, if any */
> > -               if (fi->last_readdir) {
> > -                       ceph_mdsc_put_request(fi->last_readdir);
> > -                       fi->last_readdir = NULL;
> > +               if (ri->last_readdir) {
> > +                       ceph_mdsc_put_request(ri->last_readdir);
> > +                       ri->last_readdir = NULL;
> >                 }
> >
> >                 if (is_hash_order(ctx->pos)) {
> > @@ -373,7 +379,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >                 }
> >
> >                 dout("readdir fetching %llx.%llx frag %x offset '%s'\n",
> > -                    ceph_vinop(inode), frag, fi->last_name);
> > +                    ceph_vinop(inode), frag, ri->last_name);
> >                 req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
> >                 if (IS_ERR(req))
> >                         return PTR_ERR(req);
> > @@ -389,8 +395,8 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >                         __set_bit(CEPH_MDS_R_DIRECT_IS_HASH, &req->r_req_flags);
> >                         req->r_inode_drop = CEPH_CAP_FILE_EXCL;
> >                 }
> > -               if (fi->last_name) {
> > -                       req->r_path2 = kstrdup(fi->last_name, GFP_KERNEL);
> > +               if (ri->last_name) {
> > +                       req->r_path2 = kstrdup(ri->last_name, GFP_KERNEL);
> >                         if (!req->r_path2) {
> >                                 ceph_mdsc_put_request(req);
> >                                 return -ENOMEM;
> > @@ -400,10 +406,10 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >                                 cpu_to_le32(fpos_hash(ctx->pos));
> >                 }
> >
> > -               req->r_dir_release_cnt = fi->dir_release_count;
> > -               req->r_dir_ordered_cnt = fi->dir_ordered_count;
> > -               req->r_readdir_cache_idx = fi->readdir_cache_idx;
> > -               req->r_readdir_offset = fi->next_offset;
> > +               req->r_dir_release_cnt = ri->dir_release_count;
> > +               req->r_dir_ordered_cnt = ri->dir_ordered_count;
> > +               req->r_readdir_cache_idx = ri->readdir_cache_idx;
> > +               req->r_readdir_offset = ri->next_offset;
> >                 req->r_args.readdir.frag = cpu_to_le32(frag);
> >                 req->r_args.readdir.flags =
> >                                 cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS);
> > @@ -427,35 +433,35 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >                 if (le32_to_cpu(rinfo->dir_dir->frag) != frag) {
> >                         frag = le32_to_cpu(rinfo->dir_dir->frag);
> >                         if (!rinfo->hash_order) {
> > -                               fi->next_offset = req->r_readdir_offset;
> > +                               ri->next_offset = req->r_readdir_offset;
> >                                 /* adjust ctx->pos to beginning of frag */
> >                                 ctx->pos = ceph_make_fpos(frag,
> > -                                                         fi->next_offset,
> > +                                                         ri->next_offset,
> >                                                           false);
> >                         }
> >                 }
> >
> > -               fi->frag = frag;
> > -               fi->last_readdir = req;
> > +               ri->frag = frag;
> > +               ri->last_readdir = req;
> >
> >                 if (test_bit(CEPH_MDS_R_DID_PREPOPULATE, &req->r_req_flags)) {
> > -                       fi->readdir_cache_idx = req->r_readdir_cache_idx;
> > -                       if (fi->readdir_cache_idx < 0) {
> > +                       ri->readdir_cache_idx = req->r_readdir_cache_idx;
> > +                       if (ri->readdir_cache_idx < 0) {
> >                                 /* preclude from marking dir ordered */
> > -                               fi->dir_ordered_count = 0;
> > +                               ri->dir_ordered_count = 0;
> >                         } else if (ceph_frag_is_leftmost(frag) &&
> > -                                  fi->next_offset == 2) {
> > +                                  ri->next_offset == 2) {
> >                                 /* note dir version at start of readdir so
> >                                  * we can tell if any dentries get dropped */
> > -                               fi->dir_release_count = req->r_dir_release_cnt;
> > -                               fi->dir_ordered_count = req->r_dir_ordered_cnt;
> > +                               ri->dir_release_count = req->r_dir_release_cnt;
> > +                               ri->dir_ordered_count = req->r_dir_ordered_cnt;
> >                         }
> >                 } else {
> >                         dout("readdir !did_prepopulate");
> >                         /* disable readdir cache */
> > -                       fi->readdir_cache_idx = -1;
> > +                       ri->readdir_cache_idx = -1;
> >                         /* preclude from marking dir complete */
> > -                       fi->dir_release_count = 0;
> > +                       ri->dir_release_count = 0;
> >                 }
> >
> >                 /* note next offset and last dentry name */
> > @@ -469,14 +475,14 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >                         if (err)
> >                                 return err;
> >                 } else if (req->r_reply_info.dir_end) {
> > -                       fi->next_offset = 2;
> > +                       ri->next_offset = 2;
> >                         /* keep last name */
> >                 }
> >         }
> >
> > -       rinfo = &fi->last_readdir->r_reply_info;
> > +       rinfo = &ri->last_readdir->r_reply_info;
> >         dout("readdir frag %x num %d pos %llx chunk first %llx\n",
> > -            fi->frag, rinfo->dir_nr, ctx->pos,
> > +            ri->frag, rinfo->dir_nr, ctx->pos,
> >              rinfo->dir_nr ? rinfo->dir_entries[0].offset : 0LL);
> >
> >         i = 0;
> > @@ -520,27 +526,27 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >                 ctx->pos++;
> >         }
> >
> > -       ceph_mdsc_put_request(fi->last_readdir);
> > -       fi->last_readdir = NULL;
> > +       ceph_mdsc_put_request(ri->last_readdir);
> > +       ri->last_readdir = NULL;
> >
> > -       if (fi->next_offset > 2) {
> > -               frag = fi->frag;
> > +       if (ri->next_offset > 2) {
> > +               frag = ri->frag;
> >                 goto more;
> >         }
> >
> >         /* more frags? */
> > -       if (!ceph_frag_is_rightmost(fi->frag)) {
> > -               frag = ceph_frag_next(fi->frag);
> > +       if (!ceph_frag_is_rightmost(ri->frag)) {
> > +               frag = ceph_frag_next(ri->frag);
> >                 if (is_hash_order(ctx->pos)) {
> >                         loff_t new_pos = ceph_make_fpos(ceph_frag_value(frag),
> > -                                                       fi->next_offset, true);
> > +                                                       ri->next_offset, true);
> >                         if (new_pos > ctx->pos)
> >                                 ctx->pos = new_pos;
> >                         /* keep last_name */
> >                 } else {
> > -                       ctx->pos = ceph_make_fpos(frag, fi->next_offset, false);
> > -                       kfree(fi->last_name);
> > -                       fi->last_name = NULL;
> > +                       ctx->pos = ceph_make_fpos(frag, ri->next_offset, false);
> > +                       kfree(ri->last_name);
> > +                       ri->last_name = NULL;
> >                 }
> >                 dout("readdir next frag is %x\n", frag);
> >                 goto more;
> > @@ -552,20 +558,20 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >          * were released during the whole readdir, and we should have
> >          * the complete dir contents in our cache.
> >          */
> > -       if (atomic64_read(&ci->i_release_count) == fi->dir_release_count) {
> > +       if (atomic64_read(&ci->i_release_count) == ri->dir_release_count) {
> >                 spin_lock(&ci->i_ceph_lock);
> > -               if (fi->dir_ordered_count == atomic64_read(&ci->i_ordered_count)) {
> > +               if (ri->dir_ordered_count == atomic64_read(&ci->i_ordered_count)) {
> >                         dout(" marking %p complete and ordered\n", inode);
> >                         /* use i_size to track number of entries in
> >                          * readdir cache */
> > -                       BUG_ON(fi->readdir_cache_idx < 0);
> > -                       i_size_write(inode, fi->readdir_cache_idx *
> > +                       BUG_ON(ri->readdir_cache_idx < 0);
> > +                       i_size_write(inode, ri->readdir_cache_idx *
> >                                      sizeof(struct dentry*));
> >                 } else {
> >                         dout(" marking %p complete\n", inode);
> >                 }
> > -               __ceph_dir_set_complete(ci, fi->dir_release_count,
> > -                                       fi->dir_ordered_count);
> > +               __ceph_dir_set_complete(ci, ri->dir_release_count,
> > +                                       ri->dir_ordered_count);
> >                 spin_unlock(&ci->i_ceph_lock);
> >         }
> >
> > @@ -575,15 +581,17 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
> >
> >  static void reset_readdir(struct ceph_file_info *fi)
> >  {
> > -       if (fi->last_readdir) {
> > -               ceph_mdsc_put_request(fi->last_readdir);
> > -               fi->last_readdir = NULL;
> > +       struct ceph_readdir_info *ri = fi->readdir_info;
> > +
> > +       if (ri->last_readdir) {
> > +               ceph_mdsc_put_request(ri->last_readdir);
> > +               ri->last_readdir = NULL;
> >         }
> > -       kfree(fi->last_name);
> > -       fi->last_name = NULL;
> > -       fi->dir_release_count = 0;
> > -       fi->readdir_cache_idx = -1;
> > -       fi->next_offset = 2;  /* compensate for . and .. */
> > +       kfree(ri->last_name);
> > +       ri->last_name = NULL;
> > +       ri->dir_release_count = 0;
> > +       ri->readdir_cache_idx = -1;
> > +       ri->next_offset = 2;  /* compensate for . and .. */
> >         fi->flags &= ~CEPH_F_ATEND;
> >  }
> >
> > @@ -594,16 +602,18 @@ static void reset_readdir(struct ceph_file_info *fi)
> >  static bool need_reset_readdir(struct ceph_file_info *fi, loff_t new_pos)
> >  {
> >         struct ceph_mds_reply_info_parsed *rinfo;
> > +       struct ceph_readdir_info *ri = fi->readdir_info;
> >         loff_t chunk_offset;
> > +
> >         if (new_pos == 0)
> >                 return true;
> >         if (is_hash_order(new_pos)) {
> >                 /* no need to reset last_name for a forward seek when
> >                  * dentries are sotred in hash order */
> > -       } else if (fi->frag != fpos_frag(new_pos)) {
> > +       } else if (ri->frag != fpos_frag(new_pos)) {
> >                 return true;
> >         }
> > -       rinfo = fi->last_readdir ? &fi->last_readdir->r_reply_info : NULL;
> > +       rinfo = ri->last_readdir ? &ri->last_readdir->r_reply_info : NULL;
> >         if (!rinfo || !rinfo->dir_nr)
> >                 return true;
> >         chunk_offset = rinfo->dir_entries[0].offset;
> > @@ -614,6 +624,7 @@ static bool need_reset_readdir(struct ceph_file_info *fi, loff_t new_pos)
> >  static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence)
> >  {
> >         struct ceph_file_info *fi = file->private_data;
> > +       struct ceph_readdir_info *ri = fi->readdir_info;
> >         struct inode *inode = file->f_mapping->host;
> >         loff_t retval;
> >
> > @@ -637,8 +648,8 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence)
> >                 } else if (is_hash_order(offset) && offset > file->f_pos) {
> >                         /* for hash offset, we don't know if a forward seek
> >                          * is within same frag */
> > -                       fi->dir_release_count = 0;
> > -                       fi->readdir_cache_idx = -1;
> > +                       ri->dir_release_count = 0;
> > +                       ri->readdir_cache_idx = -1;
> >                 }
> >
> >                 if (offset != file->f_pos) {
> > @@ -1371,6 +1382,7 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
> >                              loff_t *ppos)
> >  {
> >         struct ceph_file_info *cf = file->private_data;
> > +       struct ceph_readdir_info *ri = cf->readdir_info;
> >         struct inode *inode = file_inode(file);
> >         struct ceph_inode_info *ci = ceph_inode(inode);
> >         int left;
> > @@ -1379,12 +1391,12 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
> >         if (!ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT))
> >                 return -EISDIR;
> >
> > -       if (!cf->dir_info) {
> > -               cf->dir_info = kmalloc(bufsize, GFP_KERNEL);
> > -               if (!cf->dir_info)
> > +       if (!ri->dir_info) {
> > +               ri->dir_info = kmalloc(bufsize, GFP_KERNEL);
> > +               if (!ri->dir_info)
> >                         return -ENOMEM;
> > -               cf->dir_info_len =
> > -                       snprintf(cf->dir_info, bufsize,
> > +               ri->dir_info_len =
> > +                       snprintf(ri->dir_info, bufsize,
> >                                 "entries:   %20lld\n"
> >                                 " files:    %20lld\n"
> >                                 " subdirs:  %20lld\n"
> > @@ -1404,10 +1416,10 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
> >                                 (long)ci->i_rctime.tv_nsec);
> >         }
> >
> > -       if (*ppos >= cf->dir_info_len)
> > +       if (*ppos >= ri->dir_info_len)
> >                 return 0;
> > -       size = min_t(unsigned, size, cf->dir_info_len-*ppos);
> > -       left = copy_to_user(buf, cf->dir_info + *ppos, size);
> > +       size = min_t(unsigned int, size, ri->dir_info_len-*ppos);
> > +       left = copy_to_user(buf, ri->dir_info + *ppos, size);
> >         if (left == size)
> >                 return -EFAULT;
> >         *ppos += (size - left);
> > diff --git a/fs/ceph/file.c b/fs/ceph/file.c
> > index 6639926..611aaef 100644
> > --- a/fs/ceph/file.c
> > +++ b/fs/ceph/file.c
> > @@ -159,36 +159,60 @@ static size_t dio_get_pagev_size(const struct iov_iter *it)
> >         return req;
> >  }
> >
> > +
> > +static int ceph_init_file_info(struct inode *inode,
> > +                       struct file *file, int fmode)
> > +{
> > +       struct ceph_file_info *fi;
> > +
> > +       dout("init_file inode %p file %p mode 0%o (%s)\n", inode, file,
> > +               inode->i_mode, S_ISREG(inode->i_mode) ? "regular" : "dir");
> > +
> > +       BUG_ON(inode->i_fop->release != ceph_release);
> > +
> > +       fi = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
> > +       if (!fi) {
> > +               ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
> > +               return -ENOMEM;
> > +       }
> > +
> > +       if (S_ISDIR(inode->i_mode)) {
> > +               fi->readdir_info = kmem_cache_zalloc(ceph_readdir_cachep,
> > +                                                       GFP_KERNEL);
> > +               if (!fi->readdir_info) {
> > +                       kmem_cache_free(ceph_file_cachep, fi);
> > +                       return -ENOMEM;
> > +               }
> > +
> > +               fi->readdir_info->next_offset = 2;
> > +               fi->readdir_info->readdir_cache_idx = -1;
> > +       } else {
> > +               ceph_fscache_register_inode_cookie(inode);
> > +               ceph_fscache_file_set_cookie(inode, file);
> > +       }
> > +
> > +       fi->fmode = fmode;
> > +       spin_lock_init(&fi->rw_contexts_lock);
> > +       INIT_LIST_HEAD(&fi->rw_contexts);
> > +       file->private_data = fi;
> > +
> > +       return 0;
> > +}
> > +
> >  /*
> >   * initialize private struct file data.
> >   * if we fail, clean up by dropping fmode reference on the ceph_inode
> >   */
> >  static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
> >  {
> > -       struct ceph_file_info *cf;
> >         int ret = 0;
> >
> >         switch (inode->i_mode & S_IFMT) {
> >         case S_IFREG:
> > -               ceph_fscache_register_inode_cookie(inode);
> > -               ceph_fscache_file_set_cookie(inode, file);
> >         case S_IFDIR:
> > -               dout("init_file %p %p 0%o (regular)\n", inode, file,
> > -                    inode->i_mode);
> > -               cf = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
> > -               if (!cf) {
> > -                       ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
> > -                       return -ENOMEM;
> > -               }
> > -               cf->fmode = fmode;
> > -
> > -               spin_lock_init(&cf->rw_contexts_lock);
> > -               INIT_LIST_HEAD(&cf->rw_contexts);
> > -
> > -               cf->next_offset = 2;
> > -               cf->readdir_cache_idx = -1;
> > -               file->private_data = cf;
> > -               BUG_ON(inode->i_fop->release != ceph_release);
> > +               ret = ceph_init_file_info(inode, file, fmode);
> > +               if (ret)
> > +                       return ret;
> >                 break;
> >
> >         case S_IFLNK:
> > @@ -460,16 +484,24 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
> >  int ceph_release(struct inode *inode, struct file *file)
> >  {
> >         struct ceph_inode_info *ci = ceph_inode(inode);
> > -       struct ceph_file_info *cf = file->private_data;
> > +       struct ceph_file_info *fi = file->private_data;
> > +       struct ceph_readdir_info *ri = fi->readdir_info;
> > +
> > +       dout("release inode %p file %p mode 0%o (%s)\n", inode, file,
> > +               inode->i_mode, S_ISREG(inode->i_mode) ? "regular" : "dir");
> >
> > -       dout("release inode %p file %p\n", inode, file);
> > -       ceph_put_fmode(ci, cf->fmode);
> > -       if (cf->last_readdir)
> > -               ceph_mdsc_put_request(cf->last_readdir);
> > -       kfree(cf->last_name);
> > -       kfree(cf->dir_info);
> > -       WARN_ON(!list_empty(&cf->rw_contexts));
> > -       kmem_cache_free(ceph_file_cachep, cf);
> > +       WARN_ON(!list_empty(&fi->rw_contexts));
> > +
> > +       ceph_put_fmode(ci, fi->fmode);
> > +       if (ri) {
> > +               if (ri->last_readdir)
> > +                       ceph_mdsc_put_request(ri->last_readdir);
> > +               kfree(ri->last_name);
> > +               kfree(ri->dir_info);
> > +               kmem_cache_free(ceph_readdir_cachep, ri);
> > +               ri = NULL;
> > +       }
> > +       kmem_cache_free(ceph_file_cachep, fi);
> >
> >         /* wake up anyone waiting for caps on this inode */
> >         wake_up_all(&ci->i_cap_wq);
> > diff --git a/fs/ceph/super.c b/fs/ceph/super.c
> > index a62d2a9..c1732ff 100644
> > --- a/fs/ceph/super.c
> > +++ b/fs/ceph/super.c
> > @@ -677,6 +677,7 @@ static void destroy_fs_client(struct ceph_fs_client *fsc)
> >  struct kmem_cache *ceph_cap_flush_cachep;
> >  struct kmem_cache *ceph_dentry_cachep;
> >  struct kmem_cache *ceph_file_cachep;
> > +struct kmem_cache *ceph_readdir_cachep;
> >
> >  static void ceph_inode_init_once(void *foo)
> >  {
> > @@ -711,14 +712,22 @@ static int __init init_caches(void)
> >                 goto bad_dentry;
> >
> >         ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD);
> > -
> >         if (!ceph_file_cachep)
> >                 goto bad_file;
> >
> > +       ceph_readdir_cachep = KMEM_CACHE(ceph_readdir_info, SLAB_MEM_SPREAD);
> > +       if (!ceph_readdir_cachep)
> > +               goto bad_readdir;
> > +
> >         if ((error = ceph_fscache_register()))
> > -               goto bad_file;
> > +               goto bad_fscache;
> >
> >         return 0;
> > +
> > +bad_fscache:
> > +       kmem_cache_destroy(ceph_readdir_cachep);
> > +bad_readdir:
> > +       kmem_cache_destroy(ceph_file_cachep);
> >  bad_file:
> >         kmem_cache_destroy(ceph_dentry_cachep);
> >  bad_dentry:
> > @@ -743,6 +752,7 @@ static void destroy_caches(void)
> >         kmem_cache_destroy(ceph_cap_flush_cachep);
> >         kmem_cache_destroy(ceph_dentry_cachep);
> >         kmem_cache_destroy(ceph_file_cachep);
> > +       kmem_cache_destroy(ceph_readdir_cachep);
> >
> >         ceph_fscache_unregister();
> >  }
> > diff --git a/fs/ceph/super.h b/fs/ceph/super.h
> > index 21b2e5b..3a943a0 100644
> > --- a/fs/ceph/super.h
> > +++ b/fs/ceph/super.h
> > @@ -665,13 +665,7 @@ extern void ceph_reservation_status(struct ceph_fs_client *client,
> >  #define CEPH_F_SYNC     1
> >  #define CEPH_F_ATEND    2
> >
> > -struct ceph_file_info {
> > -       short fmode;     /* initialized on open */
> > -       short flags;     /* CEPH_F_* */
> > -
> > -       spinlock_t rw_contexts_lock;
> > -       struct list_head rw_contexts;
> > -
> > +struct ceph_readdir_info {
> >         /* readdir: position within the dir */
> >         u32 frag;
> >         struct ceph_mds_request *last_readdir;
> > @@ -688,6 +682,17 @@ struct ceph_file_info {
> >         int dir_info_len;
> >  };
> >
> > +struct ceph_file_info {
> > +       short fmode;     /* initialized on open */
> > +       short flags;     /* CEPH_F_* */
> > +
> > +       spinlock_t rw_contexts_lock;
> > +       struct list_head rw_contexts;
> > +
> > +       /* readdir related things */
> > +       struct ceph_readdir_info *readdir_info;
> > +};
> 
> 
> For dir file. I prefer something like:
> 
> struct ceph_dir_file_info {
>    struct ceph_file_info file;
>    ceph_readdir_info readdir.
> };
> 
> This avoids double memory allocation for dir file.

That makes sense. The only reason I keep ceph_file_info as
common interface of regular file and dir is for voiding 
detection of file type in many calling places. But if you
think it's worth, I can modify like that.

Thanks,
Chengguang.

> > +
> >  struct ceph_rw_context {
> >         struct list_head list;
> >         struct task_struct *thread;
> > diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
> > index c2ec44c..4ca23fa 100644
> > --- a/include/linux/ceph/libceph.h
> > +++ b/include/linux/ceph/libceph.h
> > @@ -262,6 +262,7 @@ static inline int calc_pages_for(u64 off, u64 len)
> >  extern struct kmem_cache *ceph_cap_flush_cachep;
> >  extern struct kmem_cache *ceph_dentry_cachep;
> >  extern struct kmem_cache *ceph_file_cachep;
> > +extern struct kmem_cache *ceph_readdir_cachep;
> >
> >  /* ceph_common.c */
> >  extern bool libceph_compatible(void *data);
> > --
> > 1.8.3.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
> > the body of a message to majordomo@xxxxxxxxxxxxxxx
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [CEPH Users]     [Ceph Large]     [Information on CEPH]     [Linux BTRFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux