static ssize_t orangefs_file_write_iter(struct kiocb *iocb, struct iov_iter *iter) { struct file *file = iocb->ki_filp; loff_t pos; ssize_t rc; BUG_ON(iocb->private); gossip_debug(GOSSIP_FILE_DEBUG, "orangefs_file_write_iter\n"); inode_lock(file->f_mapping->host); /* 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, 0, 1); if (rc == -ESTALE) rc = -EIO; if (rc) { gossip_err("%s: orangefs_inode_getattr failed, " "rc:%zd:.\n", __func__, rc); goto out; } } if (file->f_pos > i_size_read(file->f_mapping->host)) orangefs_i_size_write(file->f_mapping->host, file->f_pos); rc = generic_write_checks(iocb, iter); if (rc <= 0) { gossip_err("%s: generic_write_checks failed, rc:%zd:.\n", __func__, rc); goto out; } /* * if we are appending, generic_write_checks would have updated * pos to the end of the file, so we will wait till now to set * pos... */ pos = *(&iocb->ki_pos); rc = do_readv_writev(ORANGEFS_IO_WRITE, file, &pos, iter); if (rc < 0) { gossip_err("%s: do_readv_writev failed, rc:%zd:.\n", __func__, rc); goto out; } iocb->ki_pos = pos; g_orangefs_stats.writes++; out: inode_unlock(file->f_mapping->host); return rc; }
/* * Change the file pointer position for an instance of an open file. * * \note If .llseek is overriden, we must acquire lock as described in * Documentation/filesystems/Locking. * * Future upgrade could support SEEK_DATA and SEEK_HOLE but would * require much changes to the FS */ static loff_t orangefs_file_llseek(struct file *file, loff_t offset, int origin) { int ret = -EINVAL; struct inode *inode = file_inode(file); 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(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__); return ret; } } gossip_debug(GOSSIP_FILE_DEBUG, "orangefs_file_llseek: offset is %ld | origin is %d" " | inode size is %lu\n", (long)offset, origin, (unsigned long)i_size_read(inode)); return generic_file_llseek(file, offset, origin); }
/* * Front-end to lookup the inode-cache maintained by the VFS using the ORANGEFS * file handle. * * @sb: the file system super block instance. * @ref: The ORANGEFS object for which we are trying to locate an inode structure. */ struct inode *orangefs_iget(struct super_block *sb, struct orangefs_object_kref *ref) { struct inode *inode = NULL; unsigned long hash; int error; hash = orangefs_handle_hash(ref); inode = iget5_locked(sb, hash, orangefs_test_inode, orangefs_set_inode, ref); if (!inode || !(inode->i_state & I_NEW)) return inode; error = orangefs_inode_getattr(inode, 1, 1); if (error) { iget_failed(inode); return ERR_PTR(error); } inode->i_ino = hash; /* needed for stat etc */ orangefs_init_iops(inode); unlock_new_inode(inode); gossip_debug(GOSSIP_INODE_DEBUG, "iget handle %pU, fsid %d hash %ld i_ino %lu\n", &ref->khandle, ref->fs_id, hash, inode->i_ino); return inode; }
/* * Obtain attributes of an object given a dentry */ int orangefs_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags) { int ret = -ENOENT; struct inode *inode = path->dentry->d_inode; struct orangefs_inode_s *orangefs_inode = NULL; gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_getattr: called on %pd\n", path->dentry); ret = orangefs_inode_getattr(inode, 0, 0, request_mask); if (ret == 0) { generic_fillattr(inode, stat); /* override block size reported to stat */ orangefs_inode = ORANGEFS_I(inode); stat->blksize = orangefs_inode->blksize; if (request_mask & STATX_SIZE) stat->result_mask = STATX_BASIC_STATS; else stat->result_mask = STATX_BASIC_STATS & ~STATX_SIZE; } return ret; }
static int orangefs_setattr_size(struct inode *inode, struct iattr *iattr) { struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_kernel_op_s *new_op; loff_t orig_size; int ret = -EINVAL; gossip_debug(GOSSIP_INODE_DEBUG, "%s: %pU: Handle is %pU | fs_id %d | size is %llu\n", __func__, get_khandle_from_ino(inode), &orangefs_inode->refn.khandle, orangefs_inode->refn.fs_id, iattr->ia_size); /* Ensure that we have a up to date size, so we know if it changed. */ ret = orangefs_inode_getattr(inode, 0, 1); if (ret == -ESTALE) ret = -EIO; if (ret) { gossip_err("%s: orangefs_inode_getattr failed, ret:%d:.\n", __func__, ret); return ret; } orig_size = i_size_read(inode); truncate_setsize(inode, iattr->ia_size); new_op = op_alloc(ORANGEFS_VFS_OP_TRUNCATE); if (!new_op) return -ENOMEM; new_op->upcall.req.truncate.refn = orangefs_inode->refn; new_op->upcall.req.truncate.size = (__s64) iattr->ia_size; ret = service_operation(new_op, __func__, get_interruptible_flag(inode)); /* * the truncate has no downcall members to retrieve, but * the status value tells us if it went through ok or not */ gossip_debug(GOSSIP_INODE_DEBUG, "orangefs: orangefs_truncate got return value of %d\n", ret); op_release(new_op); if (ret != 0) return ret; if (orig_size != i_size_read(inode)) iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME; return ret; }
/* * Allocate an inode for a newly created file and insert it into the inode hash. */ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir, int mode, dev_t dev, struct orangefs_object_kref *ref) { unsigned long hash = orangefs_handle_hash(ref); struct inode *inode; int error; gossip_debug(GOSSIP_INODE_DEBUG, "%s:(sb is %p | MAJOR(dev)=%u | MINOR(dev)=%u mode=%o)\n", __func__, sb, MAJOR(dev), MINOR(dev), mode); inode = new_inode(sb); if (!inode) return NULL; orangefs_set_inode(inode, ref); inode->i_ino = hash; /* needed for stat etc */ error = orangefs_inode_getattr(inode, 1, 1); if (error) goto out_iput; orangefs_init_iops(inode); inode->i_mode = mode; inode->i_uid = current_fsuid(); inode->i_gid = current_fsgid(); inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_size = PAGE_SIZE; inode->i_rdev = dev; error = insert_inode_locked4(inode, hash, orangefs_test_inode, ref); if (error < 0) goto out_iput; gossip_debug(GOSSIP_INODE_DEBUG, "Initializing ACL's for inode %pU\n", get_khandle_from_ino(inode)); orangefs_init_acl(inode, dir); return inode; out_iput: iput(inode); return ERR_PTR(error); }
static int orangefs_fault(struct vm_fault *vmf) { struct file *file = vmf->vma->vm_file; int rc; rc = orangefs_inode_getattr(file->f_mapping->host, 0, 1, STATX_SIZE); if (rc == -ESTALE) rc = -EIO; if (rc) { gossip_err("%s: orangefs_inode_getattr failed, " "rc:%d:.\n", __func__, rc); return rc; } return filemap_fault(vmf); }
int orangefs_permission(struct inode *inode, int mask) { int ret; if (mask & MAY_NOT_BLOCK) return -ECHILD; gossip_debug(GOSSIP_INODE_DEBUG, "%s: refreshing\n", __func__); /* Make sure the permission (and other common attrs) are up to date. */ ret = orangefs_inode_getattr(inode, 0, 0); if (ret < 0) return ret; return generic_permission(inode, mask); }
/* * Obtain attributes of an object given a dentry */ int orangefs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *kstat) { int ret = -ENOENT; struct inode *inode = dentry->d_inode; struct orangefs_inode_s *orangefs_inode = NULL; gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_getattr: called on %pd\n", dentry); ret = orangefs_inode_getattr(inode, 0, 0); if (ret == 0) { generic_fillattr(inode, kstat); /* override block size reported to stat */ orangefs_inode = ORANGEFS_I(inode); kstat->blksize = orangefs_inode->blksize; } return ret; }