static void llu_lookup_finish_locks(struct lookup_intent *it, struct pnode *pnode) { struct inode *inode; LASSERT(it); LASSERT(pnode); inode = pnode->p_base->pb_ino; if (it->d.lustre.it_lock_mode && inode != NULL) { struct llu_sb_info *sbi; CDEBUG(D_DLMTRACE, "setting l_data to inode %p (%llu/%lu)\n", inode, (long long)llu_i2stat(inode)->st_ino, llu_i2info(inode)->lli_st_generation); sbi = llu_i2sbi(inode); md_set_lock_data(sbi->ll_md_exp, &it->d.lustre.it_lock_handle, inode, NULL); } /* drop lookup/getattr locks */ if (it->it_op & (IT_LOOKUP | IT_GETATTR)) ll_intent_release(it); }
void obdo_refresh_inode(struct inode *dst, struct obdo *src, obd_flag valid) { struct intnl_stat *st = llu_i2stat(dst); valid &= src->o_valid; if (valid & (OBD_MD_FLCTIME | OBD_MD_FLMTIME)) CDEBUG(D_INODE,"valid "LPX64", cur time "CFS_TIME_T"/"CFS_TIME_T ", new %lu/%lu\n", src->o_valid, LTIME_S(st->st_mtime), LTIME_S(st->st_ctime), (long)src->o_mtime, (long)src->o_ctime); if (valid & OBD_MD_FLATIME && src->o_atime > LTIME_S(st->st_atime)) LTIME_S(st->st_atime) = src->o_atime; if (valid & OBD_MD_FLMTIME && src->o_mtime > LTIME_S(st->st_mtime)) LTIME_S(st->st_mtime) = src->o_mtime; if (valid & OBD_MD_FLCTIME && src->o_ctime > LTIME_S(st->st_ctime)) LTIME_S(st->st_ctime) = src->o_ctime; if (valid & OBD_MD_FLSIZE && src->o_size > st->st_size) st->st_size = src->o_size; /* optimum IO size */ if (valid & OBD_MD_FLBLKSZ) st->st_blksize = src->o_blksize; /* allocation of space */ if (valid & OBD_MD_FLBLOCKS && src->o_blocks > st->st_blocks) st->st_blocks = src->o_blocks; }
int llu_file_release(struct inode *inode) { struct ll_file_data *fd; struct llu_sb_info *sbi = llu_i2sbi(inode); struct llu_inode_info *lli = llu_i2info(inode); int rc = 0, rc2; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:inode=%llu/%lu\n", (long long)llu_i2stat(inode)->st_ino, lli->lli_st_generation); if (llu_is_root_inode(inode)) RETURN(0); /* still opened by others? */ if (--lli->lli_open_count) RETURN(0); fd = lli->lli_file_data; if (!fd) /* no process opened the file after an mcreate */ RETURN(0); rc2 = llu_md_close(sbi->ll_md_exp, inode); if (rc2 && !rc) rc = rc2; RETURN(rc); }
static void llu_prepare_close(struct inode *inode, struct md_op_data *op_data, struct ll_file_data *fd) { struct obd_client_handle *och = &fd->fd_mds_och; op_data->op_attr.ia_valid = ATTR_MODE | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_CTIME_SET; if (fd->fd_flags & FMODE_WRITE) { struct llu_sb_info *sbi = llu_i2sbi(inode); if (!(sbi->ll_lco.lco_flags & OBD_CONNECT_SOM) || !S_ISREG(llu_i2stat(inode)->st_mode)) { op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS; } else { /* Inode cannot be dirty. Close the epoch. */ op_data->op_flags |= MF_EPOCH_CLOSE; /* XXX: Send SOM attributes only if they are really * changed. */ llu_done_writing_attr(inode, op_data); } } llu_pack_inode2opdata(inode, op_data, &och->och_fh); llu_prep_md_op_data(op_data, inode, NULL, NULL, 0, 0, LUSTRE_OPC_ANY); }
static int llu_dir_do_readpage(struct inode *inode, struct page *page) { struct llu_inode_info *lli = llu_i2info(inode); struct intnl_stat *st = llu_i2stat(inode); struct llu_sb_info *sbi = llu_i2sbi(inode); struct ptlrpc_request *request; struct lustre_handle lockh; struct mdt_body *body; struct lookup_intent it = { .it_op = IT_READDIR }; struct md_op_data op_data = {{ 0 }}; ldlm_policy_data_t policy = { .l_inodebits = { MDS_INODELOCK_UPDATE } }; int rc = 0; ENTRY; llu_prep_md_op_data(&op_data, inode, NULL, NULL, 0, 0, LUSTRE_OPC_ANY); rc = md_lock_match(sbi->ll_md_exp, LDLM_FL_BLOCK_GRANTED, &lli->lli_fid, LDLM_IBITS, &policy, LCK_CR, &lockh); if (!rc) { struct ldlm_enqueue_info einfo = { .ei_type = LDLM_IBITS, .ei_mode = LCK_CR, .ei_cb_bl = llu_md_blocking_ast, .ei_cb_cp = ldlm_completion_ast, .ei_cbdata = inode, }; rc = md_enqueue(sbi->ll_md_exp, &einfo, &it, &op_data, &lockh, NULL, 0, NULL, LDLM_FL_CANCEL_ON_BLOCK); request = (struct ptlrpc_request *)it.d.lustre.it_data; if (request) ptlrpc_req_finished(request); if (rc < 0) { CERROR("lock enqueue: err: %d\n", rc); RETURN(rc); } } ldlm_lock_dump_handle(D_OTHER, &lockh); op_data.op_offset = (__u64)hash_x_index(page->index, 0); op_data.op_npages = 1; rc = md_readpage(sbi->ll_md_exp, &op_data, &page, &request); if (!rc) { body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY); LASSERT(body != NULL); /* checked by md_readpage() */ if (body->valid & OBD_MD_FLSIZE) st->st_size = body->size; } else { CERROR("read_dir_page(%ld) error %d\n", page->index, rc); } ptlrpc_req_finished(request); EXIT; ldlm_lock_decref(&lockh, LCK_CR); return rc; }
static int slp_attr_get(const struct lu_env *env, struct cl_object *obj, struct cl_attr *attr) { struct inode *inode = ccc_object_inode(obj); struct intnl_stat *st = llu_i2stat(inode); attr->cat_size = st->st_size; attr->cat_blocks = st->st_blocks; attr->cat_mtime = st->st_mtime; attr->cat_atime = st->st_atime; attr->cat_ctime = st->st_ctime; /* KMS is not known by this layer */ return 0; /* layers below have to fill in the rest */ }
static int slp_object_print(const struct lu_env *env, void *cookie, lu_printer_t p, const struct lu_object *o) { struct ccc_object *obj = lu2ccc(o); struct inode *inode = obj->cob_inode; struct intnl_stat *st = NULL; if (inode) st = llu_i2stat(inode); return (*p)(env, cookie, LUSTRE_SLP_NAME"-object@%p(%p:%lu/%u)", obj, inode, st ? (unsigned long)st->st_ino : 0UL, inode ? (unsigned int)llu_i2info(inode)->lli_st_generation : 0); }
int llu_md_close(struct obd_export *md_exp, struct inode *inode) { struct llu_inode_info *lli = llu_i2info(inode); struct ll_file_data *fd = lli->lli_file_data; struct ptlrpc_request *req = NULL; struct obd_client_handle *och = &fd->fd_mds_och; struct intnl_stat *st = llu_i2stat(inode); struct md_op_data op_data = { { 0 } }; int rc; ENTRY; /* clear group lock, if present */ if (fd->fd_flags & LL_FILE_GROUP_LOCKED) llu_put_grouplock(inode, fd->fd_grouplock.cg_gid); llu_prepare_close(inode, &op_data, fd); rc = md_close(md_exp, &op_data, och->och_mod, &req); if (rc == -EAGAIN) { /* We are the last writer, so the MDS has instructed us to get * the file size and any write cookies, then close again. */ LASSERT(lli->lli_open_flags & FMODE_WRITE); rc = llu_som_update(inode, &op_data); if (rc) { CERROR("inode %llu mdc Size-on-MDS update failed: " "rc = %d\n", (long long)st->st_ino, rc); rc = 0; } } else if (rc) { CERROR("inode %llu close failed: rc %d\n", (long long)st->st_ino, rc); } else { rc = llu_objects_destroy(req, inode); if (rc) CERROR("inode %llu ll_objects destroy: rc = %d\n", (long long)st->st_ino, rc); } md_clear_open_replay_data(md_exp, och); ptlrpc_req_finished(req); och->och_fh.cookie = DEAD_HANDLE_MAGIC; lli->lli_file_data = NULL; OBD_FREE(fd, sizeof(*fd)); RETURN(rc); }
void llu_pack_inode2opdata(struct inode *inode, struct md_op_data *op_data, struct lustre_handle *fh) { struct llu_inode_info *lli = llu_i2info(inode); struct intnl_stat *st = llu_i2stat(inode); ENTRY; op_data->op_fid1 = lli->lli_fid; op_data->op_attr.ia_atime = st->st_atime; op_data->op_attr.ia_mtime = st->st_mtime; op_data->op_attr.ia_ctime = st->st_ctime; op_data->op_attr.ia_size = st->st_size; op_data->op_attr_blocks = st->st_blocks; op_data->op_attr.ia_attr_flags = lli->lli_st_flags; op_data->op_ioepoch = lli->lli_ioepoch; if (fh) op_data->op_handle = *fh; EXIT; }
/** Cliens updates SOM attributes on MDS: obd_getattr and md_setattr. */ int llu_som_update(struct inode *inode, struct md_op_data *op_data) { struct llu_inode_info *lli = llu_i2info(inode); struct llu_sb_info *sbi = llu_i2sbi(inode); struct obdo oa = { 0 }; __u32 old_flags; int rc; ENTRY; LASSERT(!(lli->lli_flags & LLIF_MDS_SIZE_LOCK)); LASSERT(sbi->ll_lco.lco_flags & OBD_CONNECT_SOM); old_flags = op_data->op_flags; op_data->op_flags = MF_SOM_CHANGE; /* If inode is already in another epoch, skip getattr from OSTs. */ if (lli->lli_ioepoch == op_data->op_ioepoch) { rc = llu_inode_getattr(inode, &oa, op_data->op_ioepoch, old_flags & MF_GETATTR_LOCK); if (rc) { oa.o_valid = 0; if (rc == -ENOENT) CDEBUG(D_INODE, "objid "LPX64" is destroyed\n", lli->lli_smd->lsm_object_id); else CERROR("inode_getattr failed (%d): unable to " "send a Size-on-MDS attribute update " "for inode %llu/%lu\n", rc, (long long)llu_i2stat(inode)->st_ino, lli->lli_st_generation); } else { CDEBUG(D_INODE, "Size-on-MDS update on "DFID"\n", PFID(&lli->lli_fid)); } /* Install attributes into op_data. */ md_from_obdo(op_data, &oa, oa.o_valid); } rc = llu_md_setattr(inode, op_data, NULL); RETURN(rc); }
static int lookup_it_finish(struct ptlrpc_request *request, int offset, struct lookup_intent *it, struct inode *parent, struct pnode *child) { struct llu_sb_info *sbi = llu_i2sbi(parent); struct inode *inode = NULL; int rc; /* libsysio require us generate inode right away if success. * so if mds created new inode for us we need make sure it * succeeded. thus for any error we can't delay to the * llu_file_open() time. */ if (it_disposition(it, DISP_OPEN_CREATE) && it_open_error(DISP_OPEN_CREATE, it)) { CDEBUG(D_INODE, "detect mds create error\n"); return it_open_error(DISP_OPEN_CREATE, it); } if (it_disposition(it, DISP_OPEN_OPEN) && it_open_error(DISP_OPEN_OPEN, it)) { CDEBUG(D_INODE, "detect mds open error\n"); /* undo which did by md_intent_lock */ if (it_disposition(it, DISP_OPEN_CREATE) && !it_open_error(DISP_OPEN_CREATE, it)) { LASSERT(request); LASSERT(atomic_read(&request->rq_refcount) > 1); CDEBUG(D_INODE, "dec a ref of req %p\n", request); ptlrpc_req_finished(request); } return it_open_error(DISP_OPEN_OPEN, it); } /* NB 1 request reference will be taken away by ll_intent_lock() * when I return */ if (!it_disposition(it, DISP_LOOKUP_NEG) || (it->it_op & IT_CREAT)) { struct lustre_md md; struct llu_inode_info *lli; struct intnl_stat *st; ENTRY; if (it_disposition(it, DISP_OPEN_CREATE)) ptlrpc_req_finished(request); rc = md_get_lustre_md(sbi->ll_md_exp, request, sbi->ll_dt_exp, sbi->ll_md_exp, &md); if (rc) RETURN(rc); inode = llu_iget(parent->i_fs, &md); if (!inode || IS_ERR(inode)) { /* free the lsm if we allocated one above */ if (md.lsm != NULL) obd_free_memmd(sbi->ll_dt_exp, &md.lsm); RETURN(inode ? PTR_ERR(inode) : -ENOMEM); } else if (md.lsm != NULL) { obd_free_memmd(sbi->ll_dt_exp, &md.lsm); } lli = llu_i2info(inode); st = llu_i2stat(inode); /* If this is a stat, get the authoritative file size */ if (it->it_op == IT_GETATTR && S_ISREG(st->st_mode) && lli->lli_has_smd) { ldlm_error_t rc; /* bug 2334: drop MDS lock before acquiring OST lock */ ll_intent_drop_lock(it); rc = cl_glimpse_size(inode); if (rc) { I_RELE(inode); RETURN(rc); } } } else { ENTRY; } /* intent will be further used in cases of open()/getattr() */ if (inode && (it->it_op & IT_OPEN)) LL_SAVE_INTENT(inode, it); child->p_base->pb_ino = inode; RETURN(0); }
static int llu_pb_revalidate(struct pnode *pnode, int flags, struct lookup_intent *it) { struct pnode_base *pb = pnode->p_base; struct md_op_data op_data = {{ 0 }}; struct ptlrpc_request *req = NULL; struct lookup_intent lookup_it = { .it_op = IT_LOOKUP }; struct obd_export *exp; int rc; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,intent=%x\n", (int)pb->pb_name.len, pb->pb_name.name, it ? it->it_op : 0); /* We don't want to cache negative dentries, so return 0 immediately. * We believe that this is safe, that negative dentries cannot be * pinned by someone else */ if (pb->pb_ino == NULL) { CDEBUG(D_INODE, "negative pb\n"); RETURN(0); } /* This is due to bad interaction with libsysio. remove this when we * switched to libbsdio XXX */ { struct llu_inode_info *lli = llu_i2info(pb->pb_ino); struct intnl_stat *st = llu_i2stat(pb->pb_ino); if (lli->lli_it) { CDEBUG(D_INODE, "inode %llu still have intent " "%p(opc 0x%x), release it\n", (long long) st->st_ino, lli->lli_it, lli->lli_it->it_op); ll_intent_release(lli->lli_it); OBD_FREE(lli->lli_it, sizeof(*lli->lli_it)); lli->lli_it = NULL; } } exp = llu_i2mdexp(pb->pb_ino); if (!it) { it = &lookup_it; it->it_op_release = ll_intent_release; } llu_prep_md_op_data(&op_data, pnode->p_parent->p_base->pb_ino, pb->pb_ino, pb->pb_name.name, pb->pb_name.len, 0, LUSTRE_OPC_ANY); rc = md_intent_lock(exp, &op_data, NULL, 0, it, flags, &req, llu_md_blocking_ast, LDLM_FL_CANCEL_ON_BLOCK); /* If req is NULL, then md_intent_lock only tried to do a lock match; * if all was well, it will return 1 if it found locks, 0 otherwise. */ if (req == NULL && rc >= 0) GOTO(out, rc); if (rc < 0) GOTO(out, rc = 0); rc = pnode_revalidate_finish(req, it, pnode); if (rc != 0) { ll_intent_release(it); GOTO(out, rc = 0); } rc = 1; /* Note: ll_intent_lock may cause a callback, check this! */ if (it->it_op & IT_OPEN) LL_SAVE_INTENT(pb->pb_ino, it); out: if (req && rc == 1) ptlrpc_req_finished(req); if (rc == 0) { LASSERT(pb->pb_ino); I_RELE(pb->pb_ino); pb->pb_ino = NULL; } else { llu_lookup_finish_locks(it, pnode); } RETURN(rc); }
int llu_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, void *data, int flag) { struct lustre_handle lockh; int rc; ENTRY; switch (flag) { case LDLM_CB_BLOCKING: ldlm_lock2handle(lock, &lockh); rc = ldlm_cli_cancel(&lockh, 0); if (rc < 0) { CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc); RETURN(rc); } break; case LDLM_CB_CANCELING: { struct inode *inode = llu_inode_from_resource_lock(lock); struct llu_inode_info *lli; struct intnl_stat *st; __u64 bits = lock->l_policy_data.l_inodebits.bits; struct lu_fid *fid; /* Inode is set to lock->l_resource->lr_lvb_inode * for mdc - bug 24555 */ LASSERT(lock->l_ast_data == NULL); /* Invalidate all dentries associated with this inode */ if (inode == NULL) break; lli = llu_i2info(inode); st = llu_i2stat(inode); if (bits & MDS_INODELOCK_UPDATE) lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK; fid = &lli->lli_fid; if (!fid_res_name_eq(fid, &lock->l_resource->lr_name)) LDLM_ERROR(lock, "data mismatch with object " DFID" (%p)", PFID(fid), inode); if (S_ISDIR(st->st_mode) && (bits & MDS_INODELOCK_UPDATE)) { CDEBUG(D_INODE, "invalidating inode %llu\n", (long long)st->st_ino); llu_invalidate_inode_pages(inode); } /* if (inode->i_sb->s_root && inode != inode->i_sb->s_root->d_inode) ll_unhash_aliases(inode); */ I_RELE(inode); break; } default: LBUG(); } RETURN(0); }
ssize_t llu_iop_filldirentries(struct inode *dir, _SYSIO_OFF_T *basep, char *buf, size_t nbytes) { struct llu_inode_info *lli = llu_i2info(dir); struct intnl_stat *st = llu_i2stat(dir); loff_t pos = *basep; struct ll_dir_chain chain; struct page *page; int filled = 0; int rc; int done; __u16 type; ENTRY; liblustre_wait_event(0); if (st->st_size == 0) { CWARN("dir size is 0?\n"); RETURN(0); } if (pos == MDS_DIR_END_OFF) /* * end-of-file. */ RETURN(0); rc = 0; done = 0; ll_dir_chain_init(&chain); page = llu_dir_read_page(dir, pos, 0, &chain); while (rc == 0 && !done) { struct lu_dirpage *dp; struct lu_dirent *ent; if (!IS_ERR(page)) { /* * If page is empty (end of directoryis reached), * use this value. */ __u64 hash = MDS_DIR_END_OFF; __u64 next; dp = page->addr; for (ent = lu_dirent_start(dp); ent != NULL && !done; ent = lu_dirent_next(ent)) { char *name; int namelen; struct lu_fid fid; __u64 ino; hash = le64_to_cpu(ent->lde_hash); namelen = le16_to_cpu(ent->lde_namelen); if (hash < pos) /* * Skip until we find target hash * value. */ continue; if (namelen == 0) /* * Skip dummy record. */ continue; fid = ent->lde_fid; name = ent->lde_name; fid_le_to_cpu(&fid, &fid); ino = cl_fid_build_ino(&fid, 0); type = ll_dirent_type_get(ent); done = filldir(buf, nbytes, name, namelen, (loff_t)hash, ino, type, &filled); } next = le64_to_cpu(dp->ldp_hash_end); OBD_PAGE_FREE(page); if (!done) { pos = next; if (pos == MDS_DIR_END_OFF) /* * End of directory reached. */ done = 1; else if (1 /* chain is exhausted*/) /* * Normal case: continue to the next * page. */ page = llu_dir_read_page(dir, pos, 1, &chain); else { /* * go into overflow page. */ } } else { pos = hash; if (filled == 0) GOTO(out, filled = -EINVAL); } } else { rc = PTR_ERR(page); CERROR("error reading dir "DFID" at %lu: rc %d\n", PFID(&lli->lli_fid), (unsigned long)pos, rc); } } lli->lli_dir_pos = (loff_t)pos; *basep = lli->lli_dir_pos; out: ll_dir_chain_fini(&chain); liblustre_wait_event(0); RETURN(filled); }
static int slp_io_start(const struct lu_env *env, const struct cl_io_slice *ios) { struct ccc_io *cio = cl2ccc_io(env, ios); struct cl_io *io = ios->cis_io; struct cl_object *obj = io->ci_obj; struct inode *inode = ccc_object_inode(obj); int err, ret; loff_t pos; long cnt; struct llu_io_group *iogroup; struct lustre_rw_params p = {0}; int iovidx; struct intnl_stat *st = llu_i2stat(inode); struct llu_inode_info *lli = llu_i2info(inode); struct llu_io_session *session = cl2slp_io(env, ios)->sio_session; int write = io->ci_type == CIT_WRITE; int exceed = 0; CLOBINVRNT(env, obj, ccc_object_invariant(obj)); if (write) { pos = io->u.ci_wr.wr.crw_pos; cnt = io->u.ci_wr.wr.crw_count; } else { pos = io->u.ci_rd.rd.crw_pos; cnt = io->u.ci_rd.rd.crw_count; } if (io->u.ci_wr.wr_append) { p.lrp_lock_mode = LCK_PW; } else { p.lrp_brw_flags = OBD_BRW_SRVLOCK; p.lrp_lock_mode = LCK_NL; } iogroup = get_io_group(inode, max_io_pages(cnt, cio->cui_nrsegs), &p); if (IS_ERR(iogroup)) RETURN(PTR_ERR(iogroup)); err = ccc_prep_size(env, obj, io, pos, cnt, &exceed); if (err != 0 || (write == 0 && exceed != 0)) GOTO(out, err); CDEBUG(D_INODE, "%s ino %lu, %lu bytes, offset "LPU64", i_size "LPU64"\n", write ? "Write" : "Read", (unsigned long)st->st_ino, cnt, (__u64)pos, (__u64)st->st_size); if (write && io->u.ci_wr.wr_append) pos = io->u.ci_wr.wr.crw_pos = st->st_size; /* XXX? Do we need to change io content too here? */ /* XXX What about if one write syscall writes at 2 different offsets? */ for (iovidx = 0; iovidx < cio->cui_nrsegs; iovidx++) { char *buf = (char *) cio->cui_iov[iovidx].iov_base; long count = cio->cui_iov[iovidx].iov_len; if (!count) continue; if (cnt < count) count = cnt; if (IS_BAD_PTR(buf) || IS_BAD_PTR(buf + count)) { GOTO(out, err = -EFAULT); } if (io->ci_type == CIT_READ) { if (/* local_lock && */ pos >= st->st_size) break; } else if (io->ci_type == CIT_WRITE) { if (pos >= lli->lli_maxbytes) { GOTO(out, err = -EFBIG); } if (pos + count >= lli->lli_maxbytes) count = lli->lli_maxbytes - pos; } else { LBUG(); } ret = llu_queue_pio(env, io, iogroup, buf, count, pos); if (ret < 0) { GOTO(out, err = ret); } else { io->ci_nob += ret; pos += ret; cnt -= ret; if (io->ci_type == CIT_WRITE) { // obd_adjust_kms(exp, lsm, pos, 0); // XXX if (pos > st->st_size) st->st_size = pos; } if (!cnt) break; } } LASSERT(cnt == 0 || io->ci_type == CIT_READ); /* libsysio should guarantee this */ if (!iogroup->lig_rc) session->lis_rwcount += iogroup->lig_rwcount; else if (!session->lis_rc) session->lis_rc = iogroup->lig_rc; err = 0; out: put_io_group(iogroup); return err; }
static int llu_queue_pio(const struct lu_env *env, struct cl_io *io, struct llu_io_group *group, char *buf, size_t count, loff_t pos) { struct cl_object *obj = io->ci_obj; struct inode *inode = ccc_object_inode(obj); struct intnl_stat *st = llu_i2stat(inode); struct obd_export *exp = llu_i2obdexp(inode); struct page *page; int rc = 0, ret_bytes = 0; struct cl_page *clp; struct cl_2queue *queue; ENTRY; if (!exp) RETURN(-EINVAL); queue = &io->ci_queue; cl_2queue_init(queue); /* prepare the pages array */ do { unsigned long index, offset, bytes; offset = (pos & ~CFS_PAGE_MASK); index = pos >> PAGE_CACHE_SHIFT; bytes = PAGE_CACHE_SIZE - offset; if (bytes > count) bytes = count; /* prevent read beyond file range */ if (/* local_lock && */ io->ci_type == CIT_READ && pos + bytes >= st->st_size) { if (pos >= st->st_size) break; bytes = st->st_size - pos; } /* prepare page for this index */ page = llu_get_user_page(index, buf - offset, offset, bytes); if (!page) { rc = -ENOMEM; break; } clp = cl_page_find(env, obj, cl_index(obj, pos), page, CPT_TRANSIENT); if (IS_ERR(clp)) { rc = PTR_ERR(clp); break; } rc = cl_page_own(env, io, clp); if (rc) { LASSERT(clp->cp_state == CPS_FREEING); cl_page_put(env, clp); break; } cl_2queue_add(queue, clp); /* drop the reference count for cl_page_find, so that the page * will be freed in cl_2queue_fini. */ cl_page_put(env, clp); cl_page_clip(env, clp, offset, offset+bytes); count -= bytes; pos += bytes; buf += bytes; group->lig_rwcount += bytes; ret_bytes += bytes; page++; } while (count); if (rc == 0) { enum cl_req_type iot; iot = io->ci_type == CIT_READ ? CRT_READ : CRT_WRITE; rc = cl_io_submit_sync(env, io, iot, queue, 0); } group->lig_rc = rc; cl_2queue_discard(env, io, queue); cl_2queue_disown(env, io, queue); cl_2queue_fini(env, queue); RETURN(ret_bytes); }
int llu_iop_open(struct pnode *pnode, int flags, mode_t mode) { struct inode *inode = pnode->p_base->pb_ino; struct llu_inode_info *lli = llu_i2info(inode); struct intnl_stat *st = llu_i2stat(inode); struct ll_file_data *fd; struct ptlrpc_request *request; struct lookup_intent *it; struct lov_stripe_md *lsm; int rc = 0; ENTRY; liblustre_wait_event(0); /* don't do anything for '/' */ if (llu_is_root_inode(inode)) RETURN(0); CDEBUG(D_VFSTRACE, "VFS Op:inode=%llu\n", (long long)st->st_ino); LL_GET_INTENT(inode, it); if (!it->d.lustre.it_disposition) { LBUG(); } rc = it_open_error(DISP_OPEN_OPEN, it); if (rc) GOTO(out_release, rc); rc = llu_local_open(lli, it); if (rc) LBUG(); if (!S_ISREG(st->st_mode)) GOTO(out_release, rc = 0); fd = lli->lli_file_data; lsm = lli->lli_smd; if (lsm) flags &= ~O_LOV_DELAY_CREATE; /*XXX: open_flags are overwritten and the previous ones are lost */ lli->lli_open_flags = flags & ~(O_CREAT | O_EXCL | O_TRUNC); out_release: request = it->d.lustre.it_data; ptlrpc_req_finished(request); it->it_op_release(it); OBD_FREE(it, sizeof(*it)); /* libsysio hasn't done anything for O_TRUNC. here we * simply simulate it as open(...); truncate(...); */ if (rc == 0 && (flags & O_TRUNC) && S_ISREG(st->st_mode)) { struct iattr attr; memset(&attr, 0, sizeof(attr)); attr.ia_size = 0; attr.ia_valid |= ATTR_SIZE | ATTR_RAW; rc = llu_setattr_raw(inode, &attr); if (rc) CERROR("error %d truncate in open()\n", rc); } liblustre_wait_event(0); RETURN(rc); }