]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/fuse/file.c
fuse: set mapping error in writepage_locked when it fails
[karo-tx-linux.git] / fs / fuse / file.c
index 995da8957f6fd760dfca75105640c69a1292e537..ab60051be6e533eb167a72e590494f0a46e3a488 100644 (file)
@@ -46,7 +46,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
 {
        struct fuse_file *ff;
 
-       ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
+       ff = kzalloc(sizeof(struct fuse_file), GFP_KERNEL);
        if (unlikely(!ff))
                return NULL;
 
@@ -58,7 +58,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
        }
 
        INIT_LIST_HEAD(&ff->write_entry);
-       atomic_set(&ff->count, 1);
+       refcount_set(&ff->count, 1);
        RB_CLEAR_NODE(&ff->polled_node);
        init_waitqueue_head(&ff->poll_wait);
 
@@ -77,7 +77,7 @@ void fuse_file_free(struct fuse_file *ff)
 
 static struct fuse_file *fuse_file_get(struct fuse_file *ff)
 {
-       atomic_inc(&ff->count);
+       refcount_inc(&ff->count);
        return ff;
 }
 
@@ -88,7 +88,7 @@ static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
 
 static void fuse_file_put(struct fuse_file *ff, bool sync)
 {
-       if (atomic_dec_and_test(&ff->count)) {
+       if (refcount_dec_and_test(&ff->count)) {
                struct fuse_req *req = ff->reserved_req;
 
                if (ff->fc->no_open) {
@@ -293,7 +293,7 @@ static int fuse_release(struct inode *inode, struct file *file)
 
 void fuse_sync_release(struct fuse_file *ff, int flags)
 {
-       WARN_ON(atomic_read(&ff->count) != 1);
+       WARN_ON(refcount_read(&ff->count) > 1);
        fuse_prepare_release(ff, flags, FUSE_RELEASE);
        /*
         * iput(NULL) is a no-op and since the refcount is 1 and everything's
@@ -609,7 +609,7 @@ static void fuse_aio_complete_req(struct fuse_conn *fc, struct fuse_req *req)
        struct fuse_io_priv *io = req->io;
        ssize_t pos = -1;
 
-       fuse_release_user_pages(req, !io->write);
+       fuse_release_user_pages(req, io->should_dirty);
 
        if (io->write) {
                if (req->misc.write.in.size != req->misc.write.out.size)
@@ -1316,7 +1316,6 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
                       loff_t *ppos, int flags)
 {
        int write = flags & FUSE_DIO_WRITE;
-       bool should_dirty = !write && iter_is_iovec(iter);
        int cuse = flags & FUSE_DIO_CUSE;
        struct file *file = io->file;
        struct inode *inode = file->f_mapping->host;
@@ -1346,6 +1345,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
                        inode_unlock(inode);
        }
 
+       io->should_dirty = !write && iter_is_iovec(iter);
        while (count) {
                size_t nres;
                fl_owner_t owner = current->files;
@@ -1360,7 +1360,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
                        nres = fuse_send_read(req, io, pos, nbytes, owner);
 
                if (!io->async)
-                       fuse_release_user_pages(req, should_dirty);
+                       fuse_release_user_pages(req, io->should_dirty);
                if (req->out.h.error) {
                        err = req->out.h.error;
                        break;
@@ -1669,6 +1669,7 @@ err_nofile:
 err_free:
        fuse_request_free(req);
 err:
+       mapping_set_error(page->mapping, error);
        end_page_writeback(page);
        return error;
 }
@@ -2083,7 +2084,8 @@ static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma)
        return generic_file_mmap(file, vma);
 }
 
-static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
+static int convert_fuse_file_lock(struct fuse_conn *fc,
+                                 const struct fuse_file_lock *ffl,
                                  struct file_lock *fl)
 {
        switch (ffl->type) {
@@ -2098,7 +2100,14 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
 
                fl->fl_start = ffl->start;
                fl->fl_end = ffl->end;
-               fl->fl_pid = ffl->pid;
+
+               /*
+                * Convert pid into the caller's pid namespace. If the pid
+                * does not map into the namespace fl_pid will get set to 0.
+                */
+               rcu_read_lock();
+               fl->fl_pid = pid_vnr(find_pid_ns(ffl->pid, fc->pid_ns));
+               rcu_read_unlock();
                break;
 
        default:
@@ -2147,7 +2156,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl)
        args.out.args[0].value = &outarg;
        err = fuse_simple_request(fc, &args);
        if (!err)
-               err = convert_fuse_file_lock(&outarg.lk, fl);
+               err = convert_fuse_file_lock(fc, &outarg.lk, fl);
 
        return err;
 }
@@ -2159,7 +2168,8 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
        FUSE_ARGS(args);
        struct fuse_lk_in inarg;
        int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
-       pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
+       struct pid *pid = fl->fl_type != F_UNLCK ? task_tgid(current) : NULL;
+       pid_t pid_nr = pid_nr_ns(pid, fc->pid_ns);
        int err;
 
        if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
@@ -2171,7 +2181,10 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
        if ((fl->fl_flags & FL_CLOSE_POSIX) == FL_CLOSE_POSIX)
                return 0;
 
-       fuse_lk_fill(&args, file, fl, opcode, pid, flock, &inarg);
+       if (pid && pid_nr == 0)
+               return -EOVERFLOW;
+
+       fuse_lk_fill(&args, file, fl, opcode, pid_nr, flock, &inarg);
        err = fuse_simple_request(fc, &args);
 
        /* locking is restartable */