rxrpc: do not pull udp headers on receive
[cascardo/linux.git] / fs / orangefs / file.c
index 7af0adb..ae92795 100644 (file)
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 
-#define wake_up_daemon_for_return(op)                  \
-do {                                                   \
-       complete(&op->done);                            \
-} while (0)
-
 /*
  * Copy to client-core's address space from the buffers specified
  * by the iovec upto total_size bytes.
@@ -26,8 +21,7 @@ do {                                                  \
  *       can futher be kernel-space or user-space addresses.
  *       or it can pointers to struct page's
  */
-static int precopy_buffers(struct orangefs_bufmap *bufmap,
-                          int buffer_index,
+static int precopy_buffers(int buffer_index,
                           struct iov_iter *iter,
                           size_t total_size)
 {
@@ -39,8 +33,7 @@ static int precopy_buffers(struct orangefs_bufmap *bufmap,
 
 
        if (total_size) {
-               ret = orangefs_bufmap_copy_from_iovec(bufmap,
-                                                     iter,
+               ret = orangefs_bufmap_copy_from_iovec(iter,
                                                      buffer_index,
                                                      total_size);
                if (ret < 0)
@@ -63,8 +56,7 @@ static int precopy_buffers(struct orangefs_bufmap *bufmap,
  *       can futher be kernel-space or user-space addresses.
  *       or it can pointers to struct page's
  */
-static int postcopy_buffers(struct orangefs_bufmap *bufmap,
-                           int buffer_index,
+static int postcopy_buffers(int buffer_index,
                            struct iov_iter *iter,
                            size_t total_size)
 {
@@ -75,8 +67,7 @@ static int postcopy_buffers(struct orangefs_bufmap *bufmap,
         * struct page pointers.
         */
        if (total_size) {
-               ret = orangefs_bufmap_copy_to_iovec(bufmap,
-                                                   iter,
+               ret = orangefs_bufmap_copy_to_iovec(iter,
                                                    buffer_index,
                                                    total_size);
                if (ret < 0)
@@ -96,8 +87,8 @@ static ssize_t wait_for_direct_io(enum ORANGEFS_io_type type, struct inode *inod
 {
        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
        struct orangefs_khandle *handle = &orangefs_inode->refn.khandle;
-       struct orangefs_bufmap *bufmap = NULL;
        struct orangefs_kernel_op_s *new_op = NULL;
+       struct iov_iter saved = *iter;
        int buffer_index = -1;
        ssize_t ret;
 
@@ -106,18 +97,18 @@ static ssize_t wait_for_direct_io(enum ORANGEFS_io_type type, struct inode *inod
                return -ENOMEM;
 
        /* synchronous I/O */
-       new_op->upcall.req.io.async_vfs_io = ORANGEFS_VFS_SYNC_IO;
        new_op->upcall.req.io.readahead_size = readahead_size;
        new_op->upcall.req.io.io_type = type;
        new_op->upcall.req.io.refn = orangefs_inode->refn;
 
 populate_shared_memory:
        /* get a shared buffer index */
-       ret = orangefs_bufmap_get(&bufmap, &buffer_index);
-       if (ret < 0) {
+       buffer_index = orangefs_bufmap_get();
+       if (buffer_index < 0) {
+               ret = buffer_index;
                gossip_debug(GOSSIP_FILE_DEBUG,
-                            "%s: orangefs_bufmap_get failure (%ld)\n",
-                            __func__, (long)ret);
+                            "%s: orangefs_bufmap_get failure (%zd)\n",
+                            __func__, ret);
                goto out;
        }
        gossip_debug(GOSSIP_FILE_DEBUG,
@@ -143,8 +134,7 @@ populate_shared_memory:
         * precopy_buffers only pertains to writes.
         */
        if (type == ORANGEFS_IO_WRITE) {
-               ret = precopy_buffers(bufmap,
-                                     buffer_index,
+               ret = precopy_buffers(buffer_index,
                                      iter,
                                      total_size);
                if (ret < 0)
@@ -174,7 +164,10 @@ populate_shared_memory:
         * a new shared memory location.
         */
        if (ret == -EAGAIN && op_state_purged(new_op)) {
-               orangefs_bufmap_put(bufmap, buffer_index);
+               orangefs_bufmap_put(buffer_index);
+               buffer_index = -1;
+               if (type == ORANGEFS_IO_WRITE)
+                       *iter = saved;
                gossip_debug(GOSSIP_FILE_DEBUG,
                             "%s:going to repopulate_shared_memory.\n",
                             __func__);
@@ -182,22 +175,60 @@ populate_shared_memory:
        }
 
        if (ret < 0) {
-               handle_io_error();
-               /*
-                * don't write an error to syslog on signaled operation
-                * termination unless we've got debugging turned on, as
-                * this can happen regularly (i.e. ctrl-c)
-                */
-               if (ret == -EINTR)
+               if (ret == -EINTR) {
+                       /*
+                        * We can't return EINTR if any data was written,
+                        * it's not POSIX. It is minimally acceptable
+                        * to give a partial write, the way NFS does.
+                        *
+                        * It would be optimal to return all or nothing,
+                        * but if a userspace write is bigger than
+                        * an IO buffer, and the interrupt occurs
+                        * between buffer writes, that would not be
+                        * possible.
+                        */
+                       switch (new_op->op_state - OP_VFS_STATE_GIVEN_UP) {
+                       /*
+                        * If the op was waiting when the interrupt
+                        * occurred, then the client-core did not
+                        * trigger the write.
+                        */
+                       case OP_VFS_STATE_WAITING:
+                               if (*offset == 0)
+                                       ret = -EINTR;
+                               else
+                                       ret = 0;
+                               break;
+                       /* 
+                        * If the op was in progress when the interrupt
+                        * occurred, then the client-core was able to
+                        * trigger the write.
+                        */
+                       case OP_VFS_STATE_INPROGR:
+                               ret = total_size;
+                               break;
+                       default:
+                               gossip_err("%s: unexpected op state :%d:.\n",
+                                          __func__,
+                                          new_op->op_state);
+                               ret = 0;
+                               break;
+                       }
                        gossip_debug(GOSSIP_FILE_DEBUG,
-                                    "%s: returning error %ld\n", __func__,
-                                    (long)ret);
-               else
+                                    "%s: got EINTR, state:%d: %p\n",
+                                    __func__,
+                                    new_op->op_state,
+                                    new_op);
+               } else {
                        gossip_err("%s: error in %s handle %pU, returning %zd\n",
                                __func__,
                                type == ORANGEFS_IO_READ ?
                                        "read from" : "write to",
                                handle, ret);
+               }
+               if (orangefs_cancel_op_in_progress(new_op))
+                       return ret;
+
                goto out;
        }
 
@@ -206,37 +237,24 @@ populate_shared_memory:
         * postcopy_buffers only pertains to reads.
         */
        if (type == ORANGEFS_IO_READ) {
-               ret = postcopy_buffers(bufmap,
-                                      buffer_index,
+               ret = postcopy_buffers(buffer_index,
                                       iter,
                                       new_op->downcall.resp.io.amt_complete);
-               if (ret < 0) {
-                       /*
-                        * put error codes in downcall so that handle_io_error()
-                        * preserves it properly
-                        */
-                       new_op->downcall.status = ret;
-                       handle_io_error();
+               if (ret < 0)
                        goto out;
-               }
        }
        gossip_debug(GOSSIP_FILE_DEBUG,
-           "%s(%pU): Amount written as returned by the sys-io call:%d\n",
+           "%s(%pU): Amount %s, returned by the sys-io call:%d\n",
            __func__,
            handle,
+           type == ORANGEFS_IO_READ ?  "read" : "written",
            (int)new_op->downcall.resp.io.amt_complete);
 
        ret = new_op->downcall.resp.io.amt_complete;
 
-       /*
-        * tell the device file owner waiting on I/O that this read has
-        * completed and it can return now.
-        */
-       wake_up_daemon_for_return(new_op);
-
 out:
        if (buffer_index >= 0) {
-               orangefs_bufmap_put(bufmap, buffer_index);
+               orangefs_bufmap_put(buffer_index);
                gossip_debug(GOSSIP_FILE_DEBUG,
                             "%s(%pU): PUT buffer_index %d\n",
                             __func__, handle, buffer_index);
@@ -332,9 +350,9 @@ static ssize_t do_readv_writev(enum ORANGEFS_io_type type, struct file *file,
                        break;
        } /*end while */
 
+out:
        if (total_count > 0)
                ret = total_count;
-out:
        if (ret > 0) {
                if (type == ORANGEFS_IO_READ) {
                        file_accessed(file);
@@ -431,11 +449,12 @@ static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *ite
 
        /* Make sure generic_write_checks sees an up to date inode size. */
        if (file->f_flags & O_APPEND) {
-               rc = orangefs_inode_getattr(file->f_mapping->host,
-                                        ORANGEFS_ATTR_SYS_SIZE);
+               rc = orangefs_inode_getattr(file->f_mapping->host, 0, 1);
+               if (rc == -ESTALE)
+                       rc = -EIO;
                if (rc) {
-                       gossip_err("%s: orangefs_inode_getattr failed, rc:%zd:.\n",
-                                  __func__, rc);
+                       gossip_err("%s: orangefs_inode_getattr failed, "
+                           "rc:%zd:.\n", __func__, rc);
                        goto out;
                }
        }
@@ -633,27 +652,23 @@ static int orangefs_fsync(struct file *file,
 static loff_t orangefs_file_llseek(struct file *file, loff_t offset, int origin)
 {
        int ret = -EINVAL;
-       struct inode *inode = file->f_path.dentry->d_inode;
-
-       if (!inode) {
-               gossip_err("orangefs_file_llseek: invalid inode (NULL)\n");
-               return ret;
-       }
+       struct inode *inode = file_inode(file);
 
-       if (origin == ORANGEFS_SEEK_END) {
+       if (origin == SEEK_END) {
                /*
                 * revalidate the inode's file size.
                 * NOTE: We are only interested in file size here,
                 * so we set mask accordingly.
                 */
-               ret = orangefs_inode_getattr(inode, ORANGEFS_ATTR_SYS_SIZE);
+               ret = orangefs_inode_getattr(file->f_mapping->host, 0, 1);
+               if (ret == -ESTALE)
+                       ret = -EIO;
                if (ret) {
                        gossip_debug(GOSSIP_FILE_DEBUG,
                                     "%s:%s:%d calling make bad inode\n",
                                     __FILE__,
                                     __func__,
                                     __LINE__);
-                       orangefs_make_bad_inode(inode);
                        return ret;
                }
        }
@@ -663,7 +678,7 @@ static loff_t orangefs_file_llseek(struct file *file, loff_t offset, int origin)
                     " | inode size is %lu\n",
                     (long)offset,
                     origin,
-                    (unsigned long)file->f_path.dentry->d_inode->i_size);
+                    (unsigned long)i_size_read(inode));
 
        return generic_file_llseek(file, offset, origin);
 }