All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Yan, Zheng" <ukernel@gmail.com>
To: Luis Henriques <lhenriques@suse.com>
Cc: ceph-devel <ceph-devel@vger.kernel.org>,
	"Yan, Zheng" <zyan@redhat.com>, Jeff Layton <jlayton@redhat.com>,
	Jan Fajerski <jfajerski@suse.com>
Subject: Re: [RFC PATCH v3 2/3] ceph: quotas: support for ceph.quota.max_files
Date: Thu, 21 Dec 2017 16:11:48 +0800	[thread overview]
Message-ID: <CAAM7YAm1XxPMjG9NzhwU+8k0OgTaWGupoCMyai9Ke8JppZfhNA@mail.gmail.com> (raw)
In-Reply-To: <20171220151841.22355-3-lhenriques@suse.com>

On Wed, Dec 20, 2017 at 11:18 PM, Luis Henriques <lhenriques@suse.com> wrote:
> This patch adds support for the max_files quota.  It hooks into all the
> ceph functions that add new filesystem objects that need to be checked
> against the quota limits.  When these limits are hit, -EDQUOT is returned.
>
> Note that we're not checking quotas on ceph_link().  ceph_link doesn't
> really create a new inode,  and since the MDS doesn't update the directory
> statistics when a new (hard) link is created (only with symlinks), they
> are not accounted as a new file.
>
> Link: http://tracker.ceph.com/issues/22372
> Signed-off-by: Luis Henriques <lhenriques@suse.com>
> ---
>  fs/ceph/dir.c   | 11 +++++++++
>  fs/ceph/file.c  |  4 +++-
>  fs/ceph/quota.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/ceph/super.h |  1 +
>  4 files changed, 84 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
> index 8a5266699b67..66550d92b1ac 100644
> --- a/fs/ceph/dir.c
> +++ b/fs/ceph/dir.c
> @@ -818,6 +818,9 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
>         if (ceph_snap(dir) != CEPH_NOSNAP)
>                 return -EROFS;
>
> +       if (ceph_quota_is_max_files_exceeded(dir))
> +               return -EDQUOT;
> +
>         err = ceph_pre_init_acls(dir, &mode, &acls);
>         if (err < 0)
>                 return err;
> @@ -871,6 +874,9 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
>         if (ceph_snap(dir) != CEPH_NOSNAP)
>                 return -EROFS;
>
> +       if (ceph_quota_is_max_files_exceeded(dir))
> +               return -EDQUOT;
> +
>         dout("symlink in dir %p dentry %p to '%s'\n", dir, dentry, dest);
>         req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SYMLINK, USE_AUTH_MDS);
>         if (IS_ERR(req)) {
> @@ -920,6 +926,11 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
>                 goto out;
>         }
>
> +       if (ceph_quota_is_max_files_exceeded(dir)) {
> +               err = -EDQUOT;
> +               goto out;
> +       }
> +
>         mode |= S_IFDIR;
>         err = ceph_pre_init_acls(dir, &mode, &acls);
>         if (err < 0)
> diff --git a/fs/ceph/file.c b/fs/ceph/file.c
> index 5c17125f45c7..5a77a66e3d6b 100644
> --- a/fs/ceph/file.c
> +++ b/fs/ceph/file.c
> @@ -371,7 +371,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
>         struct ceph_mds_request *req;
>         struct dentry *dn;
>         struct ceph_acls_info acls = {};
> -       int mask;
> +       int mask;
>         int err;
>
>         dout("atomic_open %p dentry %p '%pd' %s flags %d mode 0%o\n",
> @@ -382,6 +382,8 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
>                 return -ENAMETOOLONG;
>
>         if (flags & O_CREAT) {
> +               if (ceph_quota_is_max_files_exceeded(dir))
> +                       return -EDQUOT;
>                 err = ceph_pre_init_acls(dir, &mode, &acls);
>                 if (err < 0)
>                         return err;
> diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c
> index 7bde6e85b609..06b3268f8f7f 100644
> --- a/fs/ceph/quota.c
> +++ b/fs/ceph/quota.c
> @@ -61,3 +61,72 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc,
>
>         iput(inode);
>  }
> +
> +enum quota_check_op {
> +       QUOTA_CHECK_MAX_FILES_OP /* check quota max_files limit */
> +};
> +
> +/*
> + * check_quota_exceeded() will walk up the snaprealm hierarchy and, for each
> + * realm, it will execute quota check operation defined by the 'op' parameter.
> + * The snaprealm walk is interrupted if the quota check detects that the quota
> + * is exceeded or if the root inode is reached.
> + */
> +static bool check_quota_exceeded(struct inode *inode, enum quota_check_op op,
> +                                loff_t size)
> +{
> +       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
> +       struct ceph_inode_info *ci;
> +       struct ceph_snap_realm *realm, *next;
> +       struct ceph_vino vino;
> +       struct inode *ino;

It's better to use name 'in'

> +       u64 max = 0, rvalue = 0;
> +       bool quota_exceeded = false, is_root = false;
> +
> +       WARN_ON(!S_ISDIR(inode->i_mode));
> +
> +       down_read(&mdsc->snap_rwsem);
> +       realm = ceph_inode(inode)->i_snap_realm;
> +       ceph_get_snap_realm(mdsc, realm);
> +       while (realm) {
> +               vino.ino = realm->ino;
> +               vino.snap = CEPH_NOSNAP;
> +               ino = ceph_find_inode(inode->i_sb, vino);
> +               if (!ino) {
> +                       pr_warn("Failed to find inode for %llu\n", vino.ino);
> +                       break;
> +               }
> +               ci = ceph_inode(ino);
> +               switch(op) {
> +               case QUOTA_CHECK_MAX_FILES_OP:
> +                       spin_lock(&ci->i_ceph_lock);
> +                       max = ci->i_max_files;
> +                       rvalue = ci->i_rfiles + ci->i_rsubdirs;
> +                       is_root = (ci->i_vino.ino == CEPH_INO_ROOT);
> +                       spin_unlock(&ci->i_ceph_lock);
> +                       quota_exceeded = (max && (rvalue >= max));
> +                       break;
> +               default:
> +                       /* Shouldn't happen */
> +                       pr_warn("Invalid quota check op (%d)\n", op);
> +                       is_root = true; /* Just break the loop */
> +               }
> +               iput(ino);
> +
> +               if (quota_exceeded || is_root)
> +                       break;
> +               next = realm->parent;
> +               ceph_get_snap_realm(mdsc, next);
> +               ceph_put_snap_realm(mdsc, realm);
> +               realm = next;
> +       }
> +       ceph_put_snap_realm(mdsc, realm);
> +       up_read(&mdsc->snap_rwsem);
> +
> +       return quota_exceeded;
> +}
> +
> +bool ceph_quota_is_max_files_exceeded(struct inode *inode)
> +{
> +       return check_quota_exceeded(inode, QUOTA_CHECK_MAX_FILES_OP, 0);
> +}
> diff --git a/fs/ceph/super.h b/fs/ceph/super.h
> index f998b7f076cf..20197e29a7f0 100644
> --- a/fs/ceph/super.h
> +++ b/fs/ceph/super.h
> @@ -1026,5 +1026,6 @@ extern void ceph_fs_debugfs_cleanup(struct ceph_fs_client *client);
>  extern void ceph_handle_quota(struct ceph_mds_client *mdsc,
>                               struct ceph_mds_session *session,
>                               struct ceph_msg *msg);
> +extern bool ceph_quota_is_max_files_exceeded(struct inode *inode);
>
>  #endif /* _FS_CEPH_SUPER_H */
> --
> To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2017-12-21  8:11 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-20 15:18 [RFC PATCH v3 0/3] ceph: kernel client cephfs quota support Luis Henriques
2017-12-20 15:18 ` [RFC PATCH v3 1/3] ceph: quota: add initial infrastructure to support cephfs quotas Luis Henriques
2017-12-21  7:58   ` Yan, Zheng
2017-12-20 15:18 ` [RFC PATCH v3 2/3] ceph: quotas: support for ceph.quota.max_files Luis Henriques
2017-12-21  8:11   ` Yan, Zheng [this message]
2017-12-20 15:18 ` [RFC PATCH v3 3/3] ceph: quota: don't allow cross-quota renames Luis Henriques
2017-12-21  8:10   ` Yan, Zheng
2017-12-21  8:21 ` [RFC PATCH v3 0/3] ceph: kernel client cephfs quota support Yan, Zheng
2017-12-21  9:32   ` Luis Henriques

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAAM7YAm1XxPMjG9NzhwU+8k0OgTaWGupoCMyai9Ke8JppZfhNA@mail.gmail.com \
    --to=ukernel@gmail.com \
    --cc=ceph-devel@vger.kernel.org \
    --cc=jfajerski@suse.com \
    --cc=jlayton@redhat.com \
    --cc=lhenriques@suse.com \
    --cc=zyan@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.