#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.
* 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)
{
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)
* 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)
{
* 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)
{
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;
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,
* 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)
* 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__);
}
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;
}
* 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);
break;
} /*end while */
+out:
if (total_count > 0)
ret = total_count;
-out:
if (ret > 0) {
if (type == ORANGEFS_IO_READ) {
file_accessed(file);
/* 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;
}
}
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;
}
}
" | 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);
}