/* * Read data from a specified offset in a file (referenced by inode). * Data may be placed either in a user or kernel buffer. */ ssize_t orangefs_inode_read(struct inode *inode, struct iov_iter *iter, loff_t *offset, loff_t readahead_size) { struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); size_t count = iov_iter_count(iter); size_t bufmap_size; ssize_t ret = -EINVAL; g_orangefs_stats.reads++; bufmap_size = orangefs_bufmap_size_query(); if (count > bufmap_size) { gossip_debug(GOSSIP_FILE_DEBUG, "%s: count is too large (%zd/%zd)!\n", __func__, count, bufmap_size); return -EINVAL; } gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU) %zd@%llu\n", __func__, &orangefs_inode->refn.khandle, count, llu(*offset)); ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, offset, iter, count, readahead_size); if (ret > 0) *offset += ret; gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): Value(%zd) returned.\n", __func__, &orangefs_inode->refn.khandle, ret); return ret; }
/* * Common entry point for read/write/readv/writev * This function will dispatch it to either the direct I/O * or buffered I/O path depending on the mount options and/or * augmented/extended metadata attached to the file. * Note: File extended attributes override any mount options. */ static ssize_t do_readv_writev(enum ORANGEFS_io_type type, struct file *file, loff_t *offset, struct iov_iter *iter) { struct inode *inode = file->f_mapping->host; struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_khandle *handle = &orangefs_inode->refn.khandle; size_t count = iov_iter_count(iter); ssize_t total_count = 0; ssize_t ret = -EINVAL; gossip_debug(GOSSIP_FILE_DEBUG, "%s-BEGIN(%pU): count(%d) after estimate_max_iovecs.\n", __func__, handle, (int)count); if (type == ORANGEFS_IO_WRITE) { gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): proceeding with offset : %llu, " "size %d\n", __func__, handle, llu(*offset), (int)count); } if (count == 0) { ret = 0; goto out; } while (iov_iter_count(iter)) { size_t each_count = iov_iter_count(iter); size_t amt_complete; /* how much to transfer in this loop iteration */ if (each_count > orangefs_bufmap_size_query()) each_count = orangefs_bufmap_size_query(); gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): size of each_count(%d)\n", __func__, handle, (int)each_count); gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): BEFORE wait_for_io: offset is %d\n", __func__, handle, (int)*offset); ret = wait_for_direct_io(type, inode, offset, iter, each_count, 0); gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): return from wait_for_io:%d\n", __func__, handle, (int)ret); if (ret < 0) goto out; *offset += ret; total_count += ret; amt_complete = ret; gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): AFTER wait_for_io: offset is %d\n", __func__, handle, (int)*offset); /* * if we got a short I/O operations, * fall out and return what we got so far */ if (amt_complete < each_count) break; } /*end while */ out: if (total_count > 0) ret = total_count; if (ret > 0) { if (type == ORANGEFS_IO_READ) { file_accessed(file); } else { SetMtimeFlag(orangefs_inode); inode->i_mtime = CURRENT_TIME; mark_inode_dirty_sync(inode); } } gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): Value(%d) returned.\n", __func__, handle, (int)ret); return ret; }
/* * Common entry point for read/write/readv/writev * This function will dispatch it to either the direct I/O * or buffered I/O path depending on the mount options and/or * augmented/extended metadata attached to the file. * Note: File extended attributes override any mount options. */ static ssize_t do_readv_writev(enum ORANGEFS_io_type type, struct file *file, loff_t *offset, struct iov_iter *iter) { struct inode *inode = file->f_mapping->host; struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_khandle *handle = &orangefs_inode->refn.khandle; size_t count = iov_iter_count(iter); ssize_t total_count = 0; ssize_t ret = -EINVAL; gossip_debug(GOSSIP_FILE_DEBUG, "%s-BEGIN(%pU): count(%d) after estimate_max_iovecs.\n", __func__, handle, (int)count); if (type == ORANGEFS_IO_WRITE) { gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): proceeding with offset : %llu, " "size %d\n", __func__, handle, llu(*offset), (int)count); } if (count == 0) { ret = 0; goto out; } while (iov_iter_count(iter)) { size_t each_count = iov_iter_count(iter); size_t amt_complete; /* how much to transfer in this loop iteration */ if (each_count > orangefs_bufmap_size_query()) each_count = orangefs_bufmap_size_query(); gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): size of each_count(%d)\n", __func__, handle, (int)each_count); gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): BEFORE wait_for_io: offset is %d\n", __func__, handle, (int)*offset); ret = wait_for_direct_io(type, inode, offset, iter, each_count, 0); gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): return from wait_for_io:%d\n", __func__, handle, (int)ret); if (ret < 0) goto out; *offset += ret; total_count += ret; amt_complete = ret; gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): AFTER wait_for_io: offset is %d\n", __func__, handle, (int)*offset); /* * if we got a short I/O operations, * fall out and return what we got so far */ if (amt_complete < each_count) break; } /*end while */ out: if (total_count > 0) ret = total_count; if (ret > 0) { if (type == ORANGEFS_IO_READ) { file_accessed(file); } else { file_update_time(file); /* * Must invalidate to ensure write loop doesn't * prevent kernel from reading updated * attribute. Size probably changed because of * the write, and other clients could update * any other attribute. */ orangefs_inode->getattr_time = jiffies - 1; } } gossip_debug(GOSSIP_FILE_DEBUG, "%s(%pU): Value(%d) returned.\n", __func__, handle, (int)ret); return ret; }