#include <linux/uio.h>
 #include "internal.h"
 
+struct ondemand_anon_file {
+       struct file *file;
+       int fd;
+};
+
 static inline void cachefiles_req_put(struct cachefiles_req *req)
 {
        if (refcount_dec_and_test(&req->ref))
        return 0;
 }
 
-static int cachefiles_ondemand_get_fd(struct cachefiles_req *req)
+static int cachefiles_ondemand_get_fd(struct cachefiles_req *req,
+                                     struct ondemand_anon_file *anon_file)
 {
        struct cachefiles_object *object;
        struct cachefiles_cache *cache;
        struct cachefiles_open *load;
-       struct file *file;
        u32 object_id;
-       int ret, fd;
+       int ret;
 
        object = cachefiles_grab_object(req->object,
                        cachefiles_obj_get_ondemand_fd);
        if (ret < 0)
                goto err;
 
-       fd = get_unused_fd_flags(O_WRONLY);
-       if (fd < 0) {
-               ret = fd;
+       anon_file->fd = get_unused_fd_flags(O_WRONLY);
+       if (anon_file->fd < 0) {
+               ret = anon_file->fd;
                goto err_free_id;
        }
 
-       file = anon_inode_getfile("[cachefiles]", &cachefiles_ondemand_fd_fops,
-                                 object, O_WRONLY);
-       if (IS_ERR(file)) {
-               ret = PTR_ERR(file);
+       anon_file->file = anon_inode_getfile("[cachefiles]",
+                               &cachefiles_ondemand_fd_fops, object, O_WRONLY);
+       if (IS_ERR(anon_file->file)) {
+               ret = PTR_ERR(anon_file->file);
                goto err_put_fd;
        }
 
        if (object->ondemand->ondemand_id > 0) {
                spin_unlock(&object->ondemand->lock);
                /* Pair with check in cachefiles_ondemand_fd_release(). */
-               file->private_data = NULL;
+               anon_file->file->private_data = NULL;
                ret = -EEXIST;
                goto err_put_file;
        }
 
-       file->f_mode |= FMODE_PWRITE | FMODE_LSEEK;
-       fd_install(fd, file);
+       anon_file->file->f_mode |= FMODE_PWRITE | FMODE_LSEEK;
 
        load = (void *)req->msg.data;
-       load->fd = fd;
+       load->fd = anon_file->fd;
        object->ondemand->ondemand_id = object_id;
        spin_unlock(&object->ondemand->lock);
 
        return 0;
 
 err_put_file:
-       fput(file);
+       fput(anon_file->file);
+       anon_file->file = NULL;
 err_put_fd:
-       put_unused_fd(fd);
+       put_unused_fd(anon_file->fd);
+       anon_file->fd = ret;
 err_free_id:
        xa_erase(&cache->ondemand_ids, object_id);
 err:
        struct cachefiles_msg *msg;
        size_t n;
        int ret = 0;
+       struct ondemand_anon_file anon_file;
        XA_STATE(xas, &cache->reqs, cache->req_id_next);
 
        xa_lock(&cache->reqs);
        xa_unlock(&cache->reqs);
 
        if (msg->opcode == CACHEFILES_OP_OPEN) {
-               ret = cachefiles_ondemand_get_fd(req);
+               ret = cachefiles_ondemand_get_fd(req, &anon_file);
                if (ret)
                        goto out;
        }
        msg->msg_id = xas.xa_index;
        msg->object_id = req->object->ondemand->ondemand_id;
 
-       if (copy_to_user(_buffer, msg, n) != 0) {
+       if (copy_to_user(_buffer, msg, n) != 0)
                ret = -EFAULT;
-               if (msg->opcode == CACHEFILES_OP_OPEN)
-                       close_fd(((struct cachefiles_open *)msg->data)->fd);
+
+       if (msg->opcode == CACHEFILES_OP_OPEN) {
+               if (ret < 0) {
+                       fput(anon_file.file);
+                       put_unused_fd(anon_file.fd);
+                       goto out;
+               }
+               fd_install(anon_file.fd, anon_file.file);
        }
 out:
        cachefiles_put_object(req->object, cachefiles_obj_put_read_req);