]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Jul 2014 15:57:17 +0000 (08:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Jul 2014 15:57:17 +0000 (08:57 -0700)
Pull fuse fixes from Miklos Szeredi:
 "This contains miscellaneous fixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: replace count*size kzalloc by kcalloc
  fuse: release temporary page if fuse_writepage_locked() failed
  fuse: restructure ->rename2()
  fuse: avoid scheduling while atomic
  fuse: handle large user and group ID
  fuse: inode: drop cast
  fuse: ignore entry-timeout on LOOKUP_REVAL
  fuse: timeout comparison fix

1  2 
fs/fuse/dev.c
fs/fuse/file.c

diff --combined fs/fuse/dev.c
index 098f97bdcf1b165282eb8b3dacf0d79380694cee,75fa055012b22d402b494e608e723474cf3ff568..ca887314aba9deb6d59811f0d19b8c9b9a0381c3
@@@ -643,9 -643,8 +643,8 @@@ struct fuse_copy_state 
        unsigned long seglen;
        unsigned long addr;
        struct page *pg;
-       void *mapaddr;
-       void *buf;
        unsigned len;
+       unsigned offset;
        unsigned move_pages:1;
  };
  
@@@ -666,23 -665,17 +665,17 @@@ static void fuse_copy_finish(struct fus
        if (cs->currbuf) {
                struct pipe_buffer *buf = cs->currbuf;
  
-               if (!cs->write) {
-                       kunmap_atomic(cs->mapaddr);
-               } else {
-                       kunmap_atomic(cs->mapaddr);
+               if (cs->write)
                        buf->len = PAGE_SIZE - cs->len;
-               }
                cs->currbuf = NULL;
-               cs->mapaddr = NULL;
-       } else if (cs->mapaddr) {
-               kunmap_atomic(cs->mapaddr);
+       } else if (cs->pg) {
                if (cs->write) {
                        flush_dcache_page(cs->pg);
                        set_page_dirty_lock(cs->pg);
                }
                put_page(cs->pg);
-               cs->mapaddr = NULL;
        }
+       cs->pg = NULL;
  }
  
  /*
   */
  static int fuse_copy_fill(struct fuse_copy_state *cs)
  {
-       unsigned long offset;
+       struct page *page;
        int err;
  
        unlock_request(cs->fc, cs->req);
  
                        BUG_ON(!cs->nr_segs);
                        cs->currbuf = buf;
-                       cs->mapaddr = kmap_atomic(buf->page);
+                       cs->pg = buf->page;
+                       cs->offset = buf->offset;
                        cs->len = buf->len;
-                       cs->buf = cs->mapaddr + buf->offset;
                        cs->pipebufs++;
                        cs->nr_segs--;
                } else {
-                       struct page *page;
                        if (cs->nr_segs == cs->pipe->buffers)
                                return -EIO;
  
                        buf->len = 0;
  
                        cs->currbuf = buf;
-                       cs->mapaddr = kmap_atomic(page);
-                       cs->buf = cs->mapaddr;
+                       cs->pg = page;
+                       cs->offset = 0;
                        cs->len = PAGE_SIZE;
                        cs->pipebufs++;
                        cs->nr_segs++;
                        cs->iov++;
                        cs->nr_segs--;
                }
-               err = get_user_pages_fast(cs->addr, 1, cs->write, &cs->pg);
+               err = get_user_pages_fast(cs->addr, 1, cs->write, &page);
                if (err < 0)
                        return err;
                BUG_ON(err != 1);
-               offset = cs->addr % PAGE_SIZE;
-               cs->mapaddr = kmap_atomic(cs->pg);
-               cs->buf = cs->mapaddr + offset;
-               cs->len = min(PAGE_SIZE - offset, cs->seglen);
+               cs->pg = page;
+               cs->offset = cs->addr % PAGE_SIZE;
+               cs->len = min(PAGE_SIZE - cs->offset, cs->seglen);
                cs->seglen -= cs->len;
                cs->addr += cs->len;
        }
@@@ -760,15 -750,20 +750,20 @@@ static int fuse_copy_do(struct fuse_cop
  {
        unsigned ncpy = min(*size, cs->len);
        if (val) {
+               void *pgaddr = kmap_atomic(cs->pg);
+               void *buf = pgaddr + cs->offset;
                if (cs->write)
-                       memcpy(cs->buf, *val, ncpy);
+                       memcpy(buf, *val, ncpy);
                else
-                       memcpy(*val, cs->buf, ncpy);
+                       memcpy(*val, buf, ncpy);
+               kunmap_atomic(pgaddr);
                *val += ncpy;
        }
        *size -= ncpy;
        cs->len -= ncpy;
-       cs->buf += ncpy;
+       cs->offset += ncpy;
        return ncpy;
  }
  
@@@ -874,8 -869,8 +869,8 @@@ static int fuse_try_move_page(struct fu
  out_fallback_unlock:
        unlock_page(newpage);
  out_fallback:
-       cs->mapaddr = kmap_atomic(buf->page);
-       cs->buf = cs->mapaddr + buf->offset;
+       cs->pg = buf->page;
+       cs->offset = buf->offset;
  
        err = lock_request(cs->fc, cs->req);
        if (err)
@@@ -1614,7 -1609,7 +1609,7 @@@ out_finish
  
  static void fuse_retrieve_end(struct fuse_conn *fc, struct fuse_req *req)
  {
 -      release_pages(req->pages, req->num_pages, 0);
 +      release_pages(req->pages, req->num_pages, false);
  }
  
  static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
diff --combined fs/fuse/file.c
index 6e16dad13e9b16de0358f8caaec9833d9f00a84b,1570dad1915d6aec0d1014d28b8c834f28064944..40ac2628ddcf46f3be8fe96ed46bb37ee6ef1c62
@@@ -933,7 -933,8 +933,7 @@@ out
        return err;
  }
  
 -static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
 -                                unsigned long nr_segs, loff_t pos)
 +static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
  {
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
         * i_size is up to date).
         */
        if (fc->auto_inval_data ||
 -          (pos + iov_length(iov, nr_segs) > i_size_read(inode))) {
 +          (iocb->ki_pos + iov_iter_count(to) > i_size_read(inode))) {
                int err;
                err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL);
                if (err)
                        return err;
        }
  
 -      return generic_file_aio_read(iocb, iov, nr_segs, pos);
 +      return generic_file_read_iter(iocb, to);
  }
  
  static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
@@@ -1088,6 -1089,8 +1088,6 @@@ static ssize_t fuse_fill_write_pages(st
                tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes);
                flush_dcache_page(page);
  
 -              mark_page_accessed(page);
 -
                if (!tmp) {
                        unlock_page(page);
                        page_cache_release(page);
@@@ -1180,17 -1183,19 +1180,17 @@@ static ssize_t fuse_perform_write(struc
        return res > 0 ? res : err;
  }
  
 -static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 -                                 unsigned long nr_segs, loff_t pos)
 +static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
  {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
 -      size_t count = 0;
 -      size_t ocount = 0;
 +      size_t count = iov_iter_count(from);
        ssize_t written = 0;
        ssize_t written_buffered = 0;
        struct inode *inode = mapping->host;
        ssize_t err;
 -      struct iov_iter i;
        loff_t endbyte = 0;
 +      loff_t pos = iocb->ki_pos;
  
        if (get_fuse_conn(inode)->writeback_cache) {
                /* Update size (EOF optimization) and mode (SUID clearing) */
                if (err)
                        return err;
  
 -              return generic_file_aio_write(iocb, iov, nr_segs, pos);
 +              return generic_file_write_iter(iocb, from);
        }
  
 -      WARN_ON(iocb->ki_pos != pos);
 -
 -      ocount = 0;
 -      err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
 -      if (err)
 -              return err;
 -
 -      count = ocount;
        mutex_lock(&inode->i_mutex);
  
        /* We can write back this queue in page reclaim */
        if (count == 0)
                goto out;
  
 +      iov_iter_truncate(from, count);
        err = file_remove_suid(file);
        if (err)
                goto out;
                goto out;
  
        if (file->f_flags & O_DIRECT) {
 -              written = generic_file_direct_write(iocb, iov, &nr_segs, pos, 
 -                                                  count, ocount);
 -              if (written < 0 || written == count)
 +              written = generic_file_direct_write(iocb, from, pos);
 +              if (written < 0 || !iov_iter_count(from))
                        goto out;
  
                pos += written;
 -              count -= written;
  
 -              iov_iter_init(&i, iov, nr_segs, count, written);
 -              written_buffered = fuse_perform_write(file, mapping, &i, pos);
 +              written_buffered = fuse_perform_write(file, mapping, from, pos);
                if (written_buffered < 0) {
                        err = written_buffered;
                        goto out;
                written += written_buffered;
                iocb->ki_pos = pos + written_buffered;
        } else {
 -              iov_iter_init(&i, iov, nr_segs, count, 0);
 -              written = fuse_perform_write(file, mapping, &i, pos);
 +              written = fuse_perform_write(file, mapping, from, pos);
                if (written >= 0)
                        iocb->ki_pos = pos + written;
        }
@@@ -1286,7 -1302,7 +1286,7 @@@ static int fuse_get_user_pages(struct f
        size_t nbytes = 0;  /* # bytes already packed in req */
  
        /* Special case for kernel I/O: can copy directly into the buffer */
 -      if (segment_eq(get_fs(), KERNEL_DS)) {
 +      if (ii->type & ITER_KVEC) {
                unsigned long user_addr = fuse_get_user_addr(ii);
                size_t frag_size = fuse_get_frag_size(ii, *nbytesp);
  
  
        while (nbytes < *nbytesp && req->num_pages < req->max_pages) {
                unsigned npages;
 -              unsigned long user_addr = fuse_get_user_addr(ii);
 -              unsigned offset = user_addr & ~PAGE_MASK;
 -              size_t frag_size = fuse_get_frag_size(ii, *nbytesp - nbytes);
 -              int ret;
 -
 +              size_t start;
                unsigned n = req->max_pages - req->num_pages;
 -              frag_size = min_t(size_t, frag_size, n << PAGE_SHIFT);
 -
 -              npages = (frag_size + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
 -              npages = clamp(npages, 1U, n);
 -
 -              ret = get_user_pages_fast(user_addr, npages, !write,
 -                                        &req->pages[req->num_pages]);
 +              ssize_t ret = iov_iter_get_pages(ii,
 +                                      &req->pages[req->num_pages],
 +                                      n * PAGE_SIZE, &start);
                if (ret < 0)
                        return ret;
  
 -              npages = ret;
 -              frag_size = min_t(size_t, frag_size,
 -                                (npages << PAGE_SHIFT) - offset);
 -              iov_iter_advance(ii, frag_size);
 +              iov_iter_advance(ii, ret);
 +              nbytes += ret;
 +
 +              ret += start;
 +              npages = (ret + PAGE_SIZE - 1) / PAGE_SIZE;
  
 -              req->page_descs[req->num_pages].offset = offset;
 +              req->page_descs[req->num_pages].offset = start;
                fuse_page_descs_length_init(req, req->num_pages, npages);
  
                req->num_pages += npages;
                req->page_descs[req->num_pages - 1].length -=
 -                      (npages << PAGE_SHIFT) - offset - frag_size;
 -
 -              nbytes += frag_size;
 +                      (PAGE_SIZE - ret) & (PAGE_SIZE - 1);
        }
  
        if (write)
  
  static inline int fuse_iter_npages(const struct iov_iter *ii_p)
  {
 -      struct iov_iter ii = *ii_p;
 -      int npages = 0;
 -
 -      while (iov_iter_count(&ii) && npages < FUSE_MAX_PAGES_PER_REQ) {
 -              unsigned long user_addr = fuse_get_user_addr(&ii);
 -              unsigned offset = user_addr & ~PAGE_MASK;
 -              size_t frag_size = iov_iter_single_seg_count(&ii);
 -
 -              npages += (frag_size + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
 -              iov_iter_advance(&ii, frag_size);
 -      }
 -
 -      return min(npages, FUSE_MAX_PAGES_PER_REQ);
 +      return iov_iter_npages(ii_p, FUSE_MAX_PAGES_PER_REQ);
  }
  
 -ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
 -                     unsigned long nr_segs, size_t count, loff_t *ppos,
 -                     int flags)
 +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;
        int cuse = flags & FUSE_DIO_CUSE;
        struct fuse_conn *fc = ff->fc;
        size_t nmax = write ? fc->max_write : fc->max_read;
        loff_t pos = *ppos;
 +      size_t count = iov_iter_count(iter);
        pgoff_t idx_from = pos >> PAGE_CACHE_SHIFT;
        pgoff_t idx_to = (pos + count - 1) >> PAGE_CACHE_SHIFT;
        ssize_t res = 0;
        struct fuse_req *req;
 -      struct iov_iter ii;
 -
 -      iov_iter_init(&ii, iov, nr_segs, count, 0);
  
        if (io->async)
 -              req = fuse_get_req_for_background(fc, fuse_iter_npages(&ii));
 +              req = fuse_get_req_for_background(fc, fuse_iter_npages(iter));
        else
 -              req = fuse_get_req(fc, fuse_iter_npages(&ii));
 +              req = fuse_get_req(fc, fuse_iter_npages(iter));
        if (IS_ERR(req))
                return PTR_ERR(req);
  
                size_t nres;
                fl_owner_t owner = current->files;
                size_t nbytes = min(count, nmax);
 -              int err = fuse_get_user_pages(req, &ii, &nbytes, write);
 +              int err = fuse_get_user_pages(req, iter, &nbytes, write);
                if (err) {
                        res = err;
                        break;
                        fuse_put_request(fc, req);
                        if (io->async)
                                req = fuse_get_req_for_background(fc,
 -                                      fuse_iter_npages(&ii));
 +                                      fuse_iter_npages(iter));
                        else
 -                              req = fuse_get_req(fc, fuse_iter_npages(&ii));
 +                              req = fuse_get_req(fc, fuse_iter_npages(iter));
                        if (IS_ERR(req))
                                break;
                }
  EXPORT_SYMBOL_GPL(fuse_direct_io);
  
  static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
 -                                const struct iovec *iov,
 -                                unsigned long nr_segs, loff_t *ppos,
 -                                size_t count)
 +                                struct iov_iter *iter,
 +                                loff_t *ppos)
  {
        ssize_t res;
        struct file *file = io->file;
        if (is_bad_inode(inode))
                return -EIO;
  
 -      res = fuse_direct_io(io, iov, nr_segs, count, ppos, 0);
 +      res = fuse_direct_io(io, iter, ppos, 0);
  
        fuse_invalidate_attr(inode);
  
@@@ -1444,26 -1485,22 +1444,26 @@@ static ssize_t fuse_direct_read(struct 
  {
        struct fuse_io_priv io = { .async = 0, .file = file };
        struct iovec iov = { .iov_base = buf, .iov_len = count };
 -      return __fuse_direct_read(&io, &iov, 1, ppos, count);
 +      struct iov_iter ii;
 +      iov_iter_init(&ii, READ, &iov, 1, count);
 +      return __fuse_direct_read(&io, &ii, ppos);
  }
  
  static ssize_t __fuse_direct_write(struct fuse_io_priv *io,
 -                                 const struct iovec *iov,
 -                                 unsigned long nr_segs, loff_t *ppos)
 +                                 struct iov_iter *iter,
 +                                 loff_t *ppos)
  {
        struct file *file = io->file;
        struct inode *inode = file_inode(file);
 -      size_t count = iov_length(iov, nr_segs);
 +      size_t count = iov_iter_count(iter);
        ssize_t res;
  
 +
        res = generic_write_checks(file, ppos, &count, 0);
 -      if (!res)
 -              res = fuse_direct_io(io, iov, nr_segs, count, ppos,
 -                                   FUSE_DIO_WRITE);
 +      if (!res) {
 +              iov_iter_truncate(iter, count);
 +              res = fuse_direct_io(io, iter, ppos, FUSE_DIO_WRITE);
 +      }
  
        fuse_invalidate_attr(inode);
  
@@@ -1477,15 -1514,13 +1477,15 @@@ static ssize_t fuse_direct_write(struc
        struct inode *inode = file_inode(file);
        ssize_t res;
        struct fuse_io_priv io = { .async = 0, .file = file };
 +      struct iov_iter ii;
 +      iov_iter_init(&ii, WRITE, &iov, 1, count);
  
        if (is_bad_inode(inode))
                return -EIO;
  
        /* Don't allow parallel writes to the same file */
        mutex_lock(&inode->i_mutex);
 -      res = __fuse_direct_write(&io, &iov, 1, ppos);
 +      res = __fuse_direct_write(&io, &ii, ppos);
        if (res > 0)
                fuse_write_update_size(inode, *ppos);
        mutex_unlock(&inode->i_mutex);
@@@ -1687,7 -1722,7 +1687,7 @@@ static int fuse_writepage_locked(struc
        error = -EIO;
        req->ff = fuse_write_file_get(fc, fi);
        if (!req->ff)
-               goto err_free;
+               goto err_nofile;
  
        fuse_write_fill(req, req->ff, page_offset(page), 0);
  
  
        return 0;
  
+ err_nofile:
+       __free_page(tmp_page);
  err_free:
        fuse_request_free(req);
  err:
@@@ -1955,8 -1992,8 +1957,8 @@@ static int fuse_writepages(struct addre
        data.ff = NULL;
  
        err = -ENOMEM;
-       data.orig_pages = kzalloc(sizeof(struct page *) *
-                                 FUSE_MAX_PAGES_PER_REQ,
+       data.orig_pages = kcalloc(FUSE_MAX_PAGES_PER_REQ,
+                                 sizeof(struct page *),
                                  GFP_NOFS);
        if (!data.orig_pages)
                goto out;
@@@ -2269,6 -2306,7 +2271,6 @@@ static int fuse_file_flock(struct file 
                struct fuse_file *ff = file->private_data;
  
                /* emulate flock with POSIX locks */
 -              fl->fl_owner = (fl_owner_t) file;
                ff->flock = true;
                err = fuse_setlk(file, fl, 1);
        }
@@@ -2339,7 -2377,7 +2341,7 @@@ static int fuse_ioctl_copy_user(struct 
        if (!bytes)
                return 0;
  
 -      iov_iter_init(&ii, iov, nr_segs, bytes, 0);
 +      iov_iter_init(&ii, to_user ? READ : WRITE, iov, nr_segs, bytes);
  
        while (iov_iter_count(&ii)) {
                struct page *page = pages[page_idx++];
@@@ -2861,8 -2899,8 +2863,8 @@@ static inline loff_t fuse_round_up(loff
  }
  
  static ssize_t
 -fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
 -                      loff_t offset, unsigned long nr_segs)
 +fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter,
 +                      loff_t offset)
  {
        ssize_t ret = 0;
        struct file *file = iocb->ki_filp;
        loff_t pos = 0;
        struct inode *inode;
        loff_t i_size;
 -      size_t count = iov_length(iov, nr_segs);
 +      size_t count = iov_iter_count(iter);
        struct fuse_io_priv *io;
  
        pos = offset;
                if (offset >= i_size)
                        return 0;
                count = min_t(loff_t, count, fuse_round_up(i_size - offset));
 +              iov_iter_truncate(iter, count);
        }
  
        io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
                io->async = false;
  
        if (rw == WRITE)
 -              ret = __fuse_direct_write(io, iov, nr_segs, &pos);
 +              ret = __fuse_direct_write(io, iter, &pos);
        else
 -              ret = __fuse_direct_read(io, iov, nr_segs, &pos, count);
 +              ret = __fuse_direct_read(io, iter, &pos);
  
        if (io->async) {
                fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
  
  static const struct file_operations fuse_file_operations = {
        .llseek         = fuse_file_llseek,
 -      .read           = do_sync_read,
 -      .aio_read       = fuse_file_aio_read,
 -      .write          = do_sync_write,
 -      .aio_write      = fuse_file_aio_write,
 +      .read           = new_sync_read,
 +      .read_iter      = fuse_file_read_iter,
 +      .write          = new_sync_write,
 +      .write_iter     = fuse_file_write_iter,
        .mmap           = fuse_file_mmap,
        .open           = fuse_open,
        .flush          = fuse_flush,