]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/ceph/file.c
ceph: quota: support for ceph.quota.max_bytes
[mirror_ubuntu-bionic-kernel.git] / fs / ceph / file.c
index 5c17125f45c786ab65aeeaa4782faedd895525a9..a51098c0fc877eed3c0e6b4e373db5908788ed02 100644 (file)
@@ -181,6 +181,10 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
                        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;
@@ -371,7 +375,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 +386,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;
@@ -464,6 +470,7 @@ int ceph_release(struct inode *inode, struct file *file)
                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);
 
        /* wake up anyone waiting for caps on this inode */
@@ -635,7 +642,8 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to,
 struct ceph_aio_request {
        struct kiocb *iocb;
        size_t total_len;
-       int write;
+       bool write;
+       bool should_dirty;
        int error;
        struct list_head osd_reqs;
        unsigned num_reqs;
@@ -714,7 +722,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req)
                if (aio_work) {
                        INIT_WORK(&aio_work->work, ceph_aio_retry_work);
                        aio_work->req = req;
-                       queue_work(ceph_inode_to_client(inode)->wb_wq,
+                       queue_work(ceph_inode_to_client(inode)->inode_wq,
                                   &aio_work->work);
                        return;
                }
@@ -745,7 +753,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req)
                }
        }
 
-       ceph_put_page_vector(osd_data->pages, num_pages, !aio_req->write);
+       ceph_put_page_vector(osd_data->pages, num_pages, aio_req->should_dirty);
        ceph_osdc_put_request(req);
 
        if (rc < 0)
@@ -842,6 +850,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
        size_t count = iov_iter_count(iter);
        loff_t pos = iocb->ki_pos;
        bool write = iov_iter_rw(iter) == WRITE;
+       bool should_dirty = !write && iter_is_iovec(iter);
 
        if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP)
                return -EROFS;
@@ -871,6 +880,11 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                size_t start = 0;
                ssize_t len;
 
+               if (write)
+                       size = min_t(u64, size, fsc->mount_options->wsize);
+               else
+                       size = min_t(u64, size, fsc->mount_options->rsize);
+
                vino = ceph_vino(inode);
                req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
                                            vino, pos, &size, 0,
@@ -886,11 +900,6 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                        break;
                }
 
-               if (write)
-                       size = min_t(u64, size, fsc->mount_options->wsize);
-               else
-                       size = min_t(u64, size, fsc->mount_options->rsize);
-
                len = size;
                pages = dio_get_pages_alloc(iter, len, &start, &num_pages);
                if (IS_ERR(pages)) {
@@ -909,6 +918,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                        if (aio_req) {
                                aio_req->iocb = iocb;
                                aio_req->write = write;
+                               aio_req->should_dirty = should_dirty;
                                INIT_LIST_HEAD(&aio_req->osd_reqs);
                                if (write) {
                                        aio_req->mtime = mtime;
@@ -966,7 +976,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                                len = ret;
                }
 
-               ceph_put_page_vector(pages, num_pages, !write);
+               ceph_put_page_vector(pages, num_pages, should_dirty);
 
                ceph_osdc_put_request(req);
                if (ret < 0)
@@ -1199,12 +1209,13 @@ again:
                        retry_op = READ_INLINE;
                }
        } else {
+               CEPH_DEFINE_RW_CONTEXT(rw_ctx, got);
                dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
                     inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len,
                     ceph_cap_string(got));
-               current->journal_info = filp;
+               ceph_add_rw_context(fi, &rw_ctx);
                ret = generic_file_read_iter(iocb, to);
-               current->journal_info = NULL;
+               ceph_del_rw_context(fi, &rw_ctx);
        }
        dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n",
             inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
@@ -1329,6 +1340,11 @@ retry_snap:
 
        pos = iocb->ki_pos;
        count = iov_iter_count(from);
+       if (ceph_quota_is_max_bytes_exceeded(inode, pos + count)) {
+               err = -EDQUOT;
+               goto out;
+       }
+
        err = file_remove_privs(file);
        if (err)
                goto out;
@@ -1659,6 +1675,12 @@ static long ceph_fallocate(struct file *file, int mode,
                goto unlock;
        }
 
+       if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)) &&
+           ceph_quota_is_max_bytes_exceeded(inode, offset + length)) {
+               ret = -EDQUOT;
+               goto unlock;
+       }
+
        if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) &&
            !(mode & FALLOC_FL_PUNCH_HOLE)) {
                ret = -ENOSPC;