static void vvp_object_size_unlock(struct cl_object *obj) { struct inode *inode = vvp_object_inode(obj); cl_object_attr_unlock(obj); ll_inode_size_unlock(inode); }
/** * Implementation of struct cl_req_operations::cro_attr_set() for VVP * layer. VVP is responsible for * * - o_[mac]time * * - o_mode * * - o_parent_seq * * - o_[ug]id * * - o_parent_oid * * - o_parent_ver * * - o_ioepoch, * */ static void vvp_req_attr_set(const struct lu_env *env, const struct cl_req_slice *slice, const struct cl_object *obj, struct cl_req_attr *attr, u64 flags) { struct inode *inode; struct obdo *oa; u32 valid_flags; oa = attr->cra_oa; inode = vvp_object_inode(obj); valid_flags = OBD_MD_FLTYPE; if (slice->crs_req->crq_type == CRT_WRITE) { if (flags & OBD_MD_FLEPOCH) { oa->o_valid |= OBD_MD_FLEPOCH; oa->o_ioepoch = ll_i2info(inode)->lli_ioepoch; valid_flags |= OBD_MD_FLMTIME | OBD_MD_FLCTIME | OBD_MD_FLUID | OBD_MD_FLGID; } } obdo_from_inode(oa, inode, valid_flags & flags); obdo_set_parent_fid(oa, &ll_i2info(inode)->lli_fid); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_INVALID_PFID)) oa->o_parent_oid++; memcpy(attr->cra_jobid, ll_i2info(inode)->lli_jobid, LUSTRE_JOBID_SIZE); }
int vvp_object_invariant(const struct cl_object *obj) { struct inode *inode = vvp_object_inode(obj); struct ll_inode_info *lli = ll_i2info(inode); return (S_ISREG(inode->i_mode) || inode->i_mode == 0) && lli->lli_clob == obj; }
/** * Helper function that if necessary adjusts file size (inode->i_size), when * position at the offset \a pos is accessed. File size can be arbitrary stale * on a Lustre client, but client at least knows KMS. If accessed area is * inside [0, KMS], set file size to KMS, otherwise glimpse file size. * * Locking: cl_isize_lock is used to serialize changes to inode size and to * protect consistency between inode size and cl_object * attributes. cl_object_size_lock() protects consistency between cl_attr's of * top-object and sub-objects. */ static int vvp_prep_size(const struct lu_env *env, struct cl_object *obj, struct cl_io *io, loff_t start, size_t count, int *exceed) { struct cl_attr *attr = vvp_env_thread_attr(env); struct inode *inode = vvp_object_inode(obj); loff_t pos = start + count - 1; loff_t kms; int result; /* * Consistency guarantees: following possibilities exist for the * relation between region being accessed and real file size at this * moment: * * (A): the region is completely inside of the file; * * (B-x): x bytes of region are inside of the file, the rest is * outside; * * (C): the region is completely outside of the file. * * This classification is stable under DLM lock already acquired by * the caller, because to change the class, other client has to take * DLM lock conflicting with our lock. Also, any updates to ->i_size * by other threads on this client are serialized by * ll_inode_size_lock(). This guarantees that short reads are handled * correctly in the face of concurrent writes and truncates. */ vvp_object_size_lock(obj); result = cl_object_attr_get(env, obj, attr); if (result == 0) { kms = attr->cat_kms; if (pos > kms) { /* * A glimpse is necessary to determine whether we * return a short read (B) or some zeroes at the end * of the buffer (C) */ vvp_object_size_unlock(obj); result = cl_glimpse_lock(env, io, inode, obj, 0); if (result == 0 && exceed) { /* If objective page index exceed end-of-file * page index, return directly. Do not expect * kernel will check such case correctly. * linux-2.6.18-128.1.1 miss to do that. * --bug 17336 */ loff_t size = i_size_read(inode); loff_t cur_index = start >> PAGE_SHIFT; loff_t size_index = (size - 1) >> PAGE_SHIFT; if ((size == 0 && cur_index != 0) || size_index < cur_index) *exceed = 1; }
static int vvp_prune(const struct lu_env *env, struct cl_object *obj) { struct inode *inode = vvp_object_inode(obj); int rc; rc = cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, CL_FSYNC_LOCAL, 1); if (rc < 0) { CDEBUG(D_VFSTRACE, DFID ": writeback failed: %d\n", PFID(lu_object_fid(&obj->co_lu)), rc); return rc; } truncate_inode_pages(inode->i_mapping, 0); return 0; }
static int vvp_object_glimpse(const struct lu_env *env, const struct cl_object *obj, struct ost_lvb *lvb) { struct inode *inode = vvp_object_inode(obj); lvb->lvb_mtime = LTIME_S(inode->i_mtime); lvb->lvb_atime = LTIME_S(inode->i_atime); lvb->lvb_ctime = LTIME_S(inode->i_ctime); /* * LU-417: Add dirty pages block count lest i_blocks reports 0, some * "cp" or "tar" on remote node may think it's a completely sparse file * and skip it. */ if (lvb->lvb_size > 0 && lvb->lvb_blocks == 0) lvb->lvb_blocks = dirty_cnt(inode); return 0; }
static void vvp_req_attr_set(const struct lu_env *env, struct cl_object *obj, struct cl_req_attr *attr) { struct inode *inode; struct obdo *oa; u64 valid_flags = OBD_MD_FLTYPE; oa = attr->cra_oa; inode = vvp_object_inode(obj); if (attr->cra_type == CRT_WRITE) valid_flags |= OBD_MD_FLMTIME | OBD_MD_FLCTIME | OBD_MD_FLUID | OBD_MD_FLGID; obdo_from_inode(oa, inode, valid_flags & attr->cra_flags); obdo_set_parent_fid(oa, &ll_i2info(inode)->lli_fid); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_INVALID_PFID)) oa->o_parent_oid++; memcpy(attr->cra_jobid, ll_i2info(inode)->lli_jobid, LUSTRE_JOBID_SIZE); }
static int vvp_attr_get(const struct lu_env *env, struct cl_object *obj, struct cl_attr *attr) { struct inode *inode = vvp_object_inode(obj); /* * lov overwrites most of these fields in * lov_attr_get()->...lov_merge_lvb_kms(), except when inode * attributes are newer. */ attr->cat_size = i_size_read(inode); attr->cat_mtime = inode->i_mtime.tv_sec; attr->cat_atime = inode->i_atime.tv_sec; attr->cat_ctime = inode->i_ctime.tv_sec; attr->cat_blocks = inode->i_blocks; attr->cat_uid = from_kuid(&init_user_ns, inode->i_uid); attr->cat_gid = from_kgid(&init_user_ns, inode->i_gid); /* KMS is not known by this layer */ return 0; /* layers below have to fill in the rest */ }
static int vvp_attr_update(const struct lu_env *env, struct cl_object *obj, const struct cl_attr *attr, unsigned valid) { struct inode *inode = vvp_object_inode(obj); if (valid & CAT_UID) inode->i_uid = make_kuid(&init_user_ns, attr->cat_uid); if (valid & CAT_GID) inode->i_gid = make_kgid(&init_user_ns, attr->cat_gid); if (valid & CAT_ATIME) inode->i_atime.tv_sec = attr->cat_atime; if (valid & CAT_MTIME) inode->i_mtime.tv_sec = attr->cat_mtime; if (valid & CAT_CTIME) inode->i_ctime.tv_sec = attr->cat_ctime; if (0 && valid & CAT_SIZE) i_size_write(inode, attr->cat_size); /* not currently necessary */ if (0 && valid & (CAT_UID|CAT_GID|CAT_SIZE)) mark_inode_dirty(inode); return 0; }
static int vvp_prune(const struct lu_env *env, struct cl_object *obj) { struct inode *inode = vvp_object_inode(obj); int rc; ENTRY; rc = cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, CL_FSYNC_LOCAL, 1); if (rc < 0) { CDEBUG(D_VFSTRACE, DFID ": writeback failed: %d\n", PFID(lu_object_fid(&obj->co_lu)), rc); RETURN(rc); } truncate_inode_pages(inode->i_mapping, 0); if (inode->i_mapping->nrpages) { CDEBUG(D_VFSTRACE, DFID ": still has %lu pages remaining\n", PFID(lu_object_fid(&obj->co_lu)), inode->i_mapping->nrpages); RETURN(-EIO); } RETURN(0); }
/* Sharing code of page_mkwrite method for rhel5 and rhel6 */ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage, bool *retry) { struct lu_env *env; struct cl_io *io; struct vvp_io *vio; int result; u16 refcheck; sigset_t set; struct inode *inode; struct ll_inode_info *lli; env = cl_env_get(&refcheck); if (IS_ERR(env)) return PTR_ERR(env); io = ll_fault_io_init(env, vma, vmpage->index, NULL); if (IS_ERR(io)) { result = PTR_ERR(io); goto out; } result = io->ci_result; if (result < 0) goto out_io; io->u.ci_fault.ft_mkwrite = 1; io->u.ci_fault.ft_writable = 1; vio = vvp_env_io(env); vio->u.fault.ft_vma = vma; vio->u.fault.ft_vmpage = vmpage; set = cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM)); inode = vvp_object_inode(io->ci_obj); lli = ll_i2info(inode); result = cl_io_loop(env, io); cfs_restore_sigs(set); if (result == 0) { struct inode *inode = file_inode(vma->vm_file); struct ll_inode_info *lli = ll_i2info(inode); lock_page(vmpage); if (!vmpage->mapping) { unlock_page(vmpage); /* page was truncated and lock was cancelled, return * ENODATA so that VM_FAULT_NOPAGE will be returned * to handle_mm_fault(). */ if (result == 0) result = -ENODATA; } else if (!PageDirty(vmpage)) { /* race, the page has been cleaned by ptlrpcd after * it was unlocked, it has to be added into dirty * cache again otherwise this soon-to-dirty page won't * consume any grants, even worse if this page is being * transferred because it will break RPC checksum. */ unlock_page(vmpage); CDEBUG(D_MMAP, "Race on page_mkwrite %p/%lu, page has been written out, retry.\n", vmpage, vmpage->index); *retry = true; result = -EAGAIN; } if (!result) set_bit(LLIF_DATA_MODIFIED, &lli->lli_flags); } out_io: cl_io_fini(env, io); out: cl_env_put(env, &refcheck); CDEBUG(D_MMAP, "%s mkwrite with %d\n", current->comm, result); LASSERT(ergo(result == 0, PageLocked(vmpage))); return result; }