Merge tag 'ceph-for-5.20-rc1' of https://github.com/ceph/ceph-client
[sfrench/cifs-2.6.git] / fs / ceph / file.c
index 284d2fda663deb8b4a20c9edcfb03d2dd78bd7c8..04fd34557de84b49612dd94f5cbd1d748ee9921a 100644 (file)
@@ -240,8 +240,7 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
        INIT_LIST_HEAD(&fi->rw_contexts);
        fi->filp_gen = READ_ONCE(ceph_inode_to_client(inode)->filp_gen);
 
-       if ((file->f_mode & FMODE_WRITE) &&
-           ci->i_inline_version != CEPH_INLINE_NONE) {
+       if ((file->f_mode & FMODE_WRITE) && ceph_has_inline_data(ci)) {
                ret = ceph_uninline_data(file);
                if (ret < 0)
                        goto error;
@@ -568,7 +567,7 @@ static void ceph_async_create_cb(struct ceph_mds_client *mdsc,
                char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
                                                  &base, 0);
 
-               pr_warn("ceph: async create failure path=(%llx)%s result=%d!\n",
+               pr_warn("async create failure path=(%llx)%s result=%d!\n",
                        base, IS_ERR(path) ? "<<bad>>" : path, result);
                ceph_mdsc_free_path(path, pathlen);
 
@@ -611,6 +610,7 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
        struct ceph_mds_reply_inode in = { };
        struct ceph_mds_reply_info_in iinfo = { .in = &in };
        struct ceph_inode_info *ci = ceph_inode(dir);
+       struct ceph_dentry_info *di = ceph_dentry(dentry);
        struct inode *inode;
        struct timespec64 now;
        struct ceph_string *pool_ns;
@@ -709,6 +709,12 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
                file->f_mode |= FMODE_CREATED;
                ret = finish_open(file, dentry, ceph_open);
        }
+
+       spin_lock(&dentry->d_lock);
+       di->flags &= ~CEPH_DENTRY_ASYNC_CREATE;
+       wake_up_bit(&di->flags, CEPH_DENTRY_ASYNC_CREATE_BIT);
+       spin_unlock(&dentry->d_lock);
+
        return ret;
 }
 
@@ -735,6 +741,15 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        if (dentry->d_name.len > NAME_MAX)
                return -ENAMETOOLONG;
 
+       err = ceph_wait_on_conflict_unlink(dentry);
+       if (err)
+               return err;
+       /*
+        * Do not truncate the file, since atomic_open is called before the
+        * permission check. The caller will do the truncation afterward.
+        */
+       flags &= ~O_TRUNC;
+
        if (flags & O_CREAT) {
                if (ceph_quota_is_max_files_exceeded(dir))
                        return -EDQUOT;
@@ -781,9 +796,16 @@ retry:
                    (req->r_dir_caps =
                      try_prep_async_create(dir, dentry, &lo,
                                            &req->r_deleg_ino))) {
+                       struct ceph_dentry_info *di = ceph_dentry(dentry);
+
                        set_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags);
                        req->r_args.open.flags |= cpu_to_le32(CEPH_O_EXCL);
                        req->r_callback = ceph_async_create_cb;
+
+                       spin_lock(&dentry->d_lock);
+                       di->flags |= CEPH_DENTRY_ASYNC_CREATE;
+                       spin_unlock(&dentry->d_lock);
+
                        err = ceph_mdsc_submit_request(mdsc, dir, req);
                        if (!err) {
                                err = ceph_finish_async_create(dir, dentry,
@@ -802,9 +824,7 @@ retry:
        }
 
        set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
-       err = ceph_mdsc_do_request(mdsc,
-                                  (flags & (O_CREAT|O_TRUNC)) ? dir : NULL,
-                                  req);
+       err = ceph_mdsc_do_request(mdsc, (flags & O_CREAT) ? dir : NULL, req);
        if (err == -ENOENT) {
                dentry = ceph_handle_snapdir(req, dentry);
                if (IS_ERR(dentry)) {
@@ -960,9 +980,8 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to,
 
                osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_off,
                                                 false, false);
-               ret = ceph_osdc_start_request(osdc, req, false);
-               if (!ret)
-                       ret = ceph_osdc_wait_request(osdc, req);
+               ceph_osdc_start_request(osdc, req);
+               ret = ceph_osdc_wait_request(osdc, req);
 
                ceph_update_read_metrics(&fsc->mdsc->metric,
                                         req->r_start_latency,
@@ -1225,7 +1244,7 @@ static void ceph_aio_retry_work(struct work_struct *work)
        req->r_inode = inode;
        req->r_priv = aio_req;
 
-       ret = ceph_osdc_start_request(req->r_osdc, req, false);
+       ceph_osdc_start_request(req->r_osdc, req);
 out:
        if (ret < 0) {
                req->r_result = ret;
@@ -1362,9 +1381,8 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                        continue;
                }
 
-               ret = ceph_osdc_start_request(req->r_osdc, req, false);
-               if (!ret)
-                       ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
+               ceph_osdc_start_request(req->r_osdc, req);
+               ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
 
                if (write)
                        ceph_update_write_metrics(metric, req->r_start_latency,
@@ -1427,8 +1445,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                                               r_private_item);
                        list_del_init(&req->r_private_item);
                        if (ret >= 0)
-                               ret = ceph_osdc_start_request(req->r_osdc,
-                                                             req, false);
+                               ceph_osdc_start_request(req->r_osdc, req);
                        if (ret < 0) {
                                req->r_result = ret;
                                ceph_aio_complete_req(req);
@@ -1541,9 +1558,8 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,
                                                false, true);
 
                req->r_mtime = mtime;
-               ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
-               if (!ret)
-                       ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
+               ceph_osdc_start_request(&fsc->client->osdc, req);
+               ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
 
                ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency,
                                          req->r_end_latency, len, ret);
@@ -1627,7 +1643,7 @@ again:
                     inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len,
                     ceph_cap_string(got));
 
-               if (ci->i_inline_version == CEPH_INLINE_NONE) {
+               if (!ceph_has_inline_data(ci)) {
                        if (!retry_op && (iocb->ki_flags & IOCB_DIRECT)) {
                                ret = ceph_direct_read_write(iocb, to,
                                                             NULL, NULL);
@@ -1890,7 +1906,7 @@ retry_snap:
                if (dirty)
                        __mark_inode_dirty(inode, dirty);
                if (ceph_quota_is_max_bytes_approaching(inode, iocb->ki_pos))
-                       ceph_check_caps(ci, 0, NULL);
+                       ceph_check_caps(ci, CHECK_CAPS_FLUSH, NULL);
        }
 
        dout("aio_write %p %llx.%llx %llu~%u  dropping cap refs on %s\n",
@@ -1930,57 +1946,15 @@ out_unlocked:
  */
 static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
 {
-       struct inode *inode = file->f_mapping->host;
-       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
-       loff_t i_size;
-       loff_t ret;
-
-       inode_lock(inode);
-
        if (whence == SEEK_END || whence == SEEK_DATA || whence == SEEK_HOLE) {
+               struct inode *inode = file_inode(file);
+               int ret;
+
                ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE, false);
                if (ret < 0)
-                       goto out;
-       }
-
-       i_size = i_size_read(inode);
-       switch (whence) {
-       case SEEK_END:
-               offset += i_size;
-               break;
-       case SEEK_CUR:
-               /*
-                * Here we special-case the lseek(fd, 0, SEEK_CUR)
-                * position-querying operation.  Avoid rewriting the "same"
-                * f_pos value back to the file because a concurrent read(),
-                * write() or lseek() might have altered it
-                */
-               if (offset == 0) {
-                       ret = file->f_pos;
-                       goto out;
-               }
-               offset += file->f_pos;
-               break;
-       case SEEK_DATA:
-               if (offset < 0 || offset >= i_size) {
-                       ret = -ENXIO;
-                       goto out;
-               }
-               break;
-       case SEEK_HOLE:
-               if (offset < 0 || offset >= i_size) {
-                       ret = -ENXIO;
-                       goto out;
-               }
-               offset = i_size;
-               break;
+                       return ret;
        }
-
-       ret = vfs_setpos(file, offset, max(i_size, fsc->max_file_size));
-
-out:
-       inode_unlock(inode);
-       return ret;
+       return generic_file_llseek(file, offset, whence);
 }
 
 static inline void ceph_zero_partial_page(
@@ -2049,12 +2023,10 @@ static int ceph_zero_partial_object(struct inode *inode,
        }
 
        req->r_mtime = inode->i_mtime;
-       ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
-       if (!ret) {
-               ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
-               if (ret == -ENOENT)
-                       ret = 0;
-       }
+       ceph_osdc_start_request(&fsc->client->osdc, req);
+       ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
+       if (ret == -ENOENT)
+               ret = 0;
        ceph_osdc_put_request(req);
 
 out:
@@ -2356,7 +2328,7 @@ static ssize_t ceph_do_objects_copy(struct ceph_inode_info *src_ci, u64 *src_off
                if (IS_ERR(req))
                        ret = PTR_ERR(req);
                else {
-                       ceph_osdc_start_request(osdc, req, false);
+                       ceph_osdc_start_request(osdc, req);
                        ret = ceph_osdc_wait_request(osdc, req);
                        ceph_update_copyfrom_metrics(&fsc->mdsc->metric,
                                                     req->r_start_latency,
@@ -2549,7 +2521,8 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,
                /* Let the MDS know about dst file size change */
                if (ceph_inode_set_size(dst_inode, dst_off) ||
                    ceph_quota_is_max_bytes_approaching(dst_inode, dst_off))
-                       ceph_check_caps(dst_ci, CHECK_CAPS_AUTHONLY, NULL);
+                       ceph_check_caps(dst_ci, CHECK_CAPS_AUTHONLY | CHECK_CAPS_FLUSH,
+                                       NULL);
        }
        /* Mark Fw dirty */
        spin_lock(&dst_ci->i_ceph_lock);