X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Ffile.c;h=e081f33dfa3f3681fafe1ba7894821bb46f0a469;hp=9332f1e32725d1c4c32e0f79fcf53f3812f2c788;hb=72a84970e6d2a2d4b3a35f2ee058511be2fda82e;hpb=2b0a34fe43bf4fce5560af61a45e5393c96070a9 diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 9332f1e..e081f33 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -58,6 +58,12 @@ struct split_param { __u16 sp_mirror_id; }; +struct pcc_param { + __u64 pa_data_version; + __u32 pa_archive_id; + __u32 pa_layout_gen; +}; + static int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg); @@ -73,6 +79,7 @@ static struct ll_file_data *ll_file_data_get(void) return NULL; fd->fd_write_failed = false; + pcc_file_init(&fd->fd_pcc_file); return fd; } @@ -139,8 +146,7 @@ static int ll_close_inode_openhandle(struct inode *inode, if (class_exp2obd(md_exp) == NULL) { CERROR("%s: invalid MDC connection handle closing "DFID"\n", - ll_get_fsname(inode->i_sb, NULL, 0), - PFID(&lli->lli_fid)); + ll_i2sbi(inode)->ll_fsname, PFID(&lli->lli_fid)); GOTO(out, rc = 0); } @@ -191,6 +197,17 @@ static int ll_close_inode_openhandle(struct inode *inode, break; } + case MDS_PCC_ATTACH: { + struct pcc_param *param = data; + + LASSERT(data != NULL); + op_data->op_bias |= MDS_HSM_RELEASE | MDS_PCC_ATTACH; + op_data->op_archive_id = param->pa_archive_id; + op_data->op_data_version = param->pa_data_version; + op_data->op_lease_handle = och->och_lease_handle; + break; + } + case MDS_HSM_RELEASE: LASSERT(data != NULL); op_data->op_bias |= MDS_HSM_RELEASE; @@ -221,6 +238,12 @@ static int ll_close_inode_openhandle(struct inode *inode, body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); if (!(body->mbo_valid & OBD_MD_CLOSE_INTENT_EXECED)) rc = -EBUSY; + + if (bias & MDS_PCC_ATTACH) { + struct pcc_param *param = data; + + param->pa_layout_gen = body->mbo_layout_gen; + } } ll_finish_md_op_data(op_data); @@ -373,6 +396,8 @@ int ll_file_release(struct inode *inode, struct file *file) RETURN(0); } + pcc_file_release(inode, file); + if (!S_ISDIR(inode->i_mode)) { if (lli->lli_clob != NULL) lov_read_and_clear_async_rc(lli->lli_clob); @@ -413,28 +438,16 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req, struct address_space *mapping = inode->i_mapping; struct page *vmpage; struct niobuf_remote *rnb; + struct mdt_body *body; char *data; - struct lustre_handle lockh; - struct ldlm_lock *lock; unsigned long index, start; struct niobuf_local lnb; - bool dom_lock = false; ENTRY; if (obj == NULL) RETURN_EXIT; - if (it->it_lock_mode != 0) { - lockh.cookie = it->it_lock_handle; - lock = ldlm_handle2lock(&lockh); - if (lock != NULL) - dom_lock = ldlm_has_dom(lock); - LDLM_LOCK_PUT(lock); - } - if (!dom_lock) - RETURN_EXIT; - if (!req_capsule_has_field(&req->rq_pill, &RMF_NIOBUF_INLINE, RCL_SERVER)) RETURN_EXIT; @@ -451,18 +464,19 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req, if (rnb->rnb_offset % PAGE_SIZE) RETURN_EXIT; - /* Server returns whole file or just file tail if it fills in - * reply buffer, in both cases total size should be inode size. + /* Server returns whole file or just file tail if it fills in reply + * buffer, in both cases total size should be equal to the file size. */ - if (rnb->rnb_offset + rnb->rnb_len < i_size_read(inode)) { - CERROR("%s: server returns off/len %llu/%u < i_size %llu\n", - ll_get_fsname(inode->i_sb, NULL, 0), rnb->rnb_offset, - rnb->rnb_len, i_size_read(inode)); + body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); + if (rnb->rnb_offset + rnb->rnb_len != body->mbo_dom_size) { + CERROR("%s: server returns off/len %llu/%u but size %llu\n", + ll_i2sbi(inode)->ll_fsname, rnb->rnb_offset, + rnb->rnb_len, body->mbo_dom_size); RETURN_EXIT; } - CDEBUG(D_INFO, "Get data along with open at %llu len %i, i_size %llu\n", - rnb->rnb_offset, rnb->rnb_len, i_size_read(inode)); + CDEBUG(D_INFO, "Get data along with open at %llu len %i, size %llu\n", + rnb->rnb_offset, rnb->rnb_len, body->mbo_dom_size); data = (char *)rnb + sizeof(*rnb); @@ -482,8 +496,8 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req, if (IS_ERR(vmpage)) { CWARN("%s: cannot fill page %lu for "DFID " with data: rc = %li\n", - ll_get_fsname(inode->i_sb, NULL, 0), - index + start, PFID(lu_object_fid(&obj->co_lu)), + ll_i2sbi(inode)->ll_fsname, index + start, + PFID(lu_object_fid(&obj->co_lu)), PTR_ERR(vmpage)); break; } @@ -498,7 +512,7 @@ static int ll_intent_file_open(struct dentry *de, void *lmm, int lmmsize, { struct ll_sb_info *sbi = ll_i2sbi(de->d_inode); struct dentry *parent = de->d_parent; - const char *name = NULL; + char *name = NULL; int len = 0; struct md_op_data *op_data; struct ptlrpc_request *req = NULL; @@ -510,21 +524,43 @@ static int ll_intent_file_open(struct dentry *de, void *lmm, int lmmsize, /* if server supports open-by-fid, or file name is invalid, don't pack * name in open request */ - if (!(exp_connect_flags(sbi->ll_md_exp) & OBD_CONNECT_OPEN_BY_FID) && - lu_name_is_valid_2(de->d_name.name, de->d_name.len)) { - name = de->d_name.name; + if (OBD_FAIL_CHECK(OBD_FAIL_LLITE_OPEN_BY_NAME) || + !(exp_connect_flags(sbi->ll_md_exp) & OBD_CONNECT_OPEN_BY_FID)) { +retry: len = de->d_name.len; + name = kmalloc(len + 1, GFP_NOFS); + if (!name) + RETURN(-ENOMEM); + + /* race here */ + spin_lock(&de->d_lock); + if (len != de->d_name.len) { + spin_unlock(&de->d_lock); + kfree(name); + goto retry; + } + memcpy(name, de->d_name.name, len); + name[len] = '\0'; + spin_unlock(&de->d_lock); + + if (!lu_name_is_valid_2(name, len)) { + kfree(name); + RETURN(-ESTALE); + } } op_data = ll_prep_md_op_data(NULL, parent->d_inode, de->d_inode, name, len, 0, LUSTRE_OPC_ANY, NULL); - if (IS_ERR(op_data)) + if (IS_ERR(op_data)) { + kfree(name); RETURN(PTR_ERR(op_data)); + } op_data->op_data = lmm; op_data->op_data_size = lmmsize; rc = md_intent_lock(sbi->ll_md_exp, op_data, itp, &req, &ll_md_blocking_ast, 0); + kfree(name); ll_finish_md_op_data(op_data); if (rc == -ESTALE) { /* reason for keep own exit path - don`t flood log @@ -549,8 +585,27 @@ static int ll_intent_file_open(struct dentry *de, void *lmm, int lmmsize, rc = ll_prep_inode(&de->d_inode, req, NULL, itp); if (!rc && itp->it_lock_mode) { - ll_dom_finish_open(de->d_inode, req, itp); + struct lustre_handle handle = {.cookie = itp->it_lock_handle}; + struct ldlm_lock *lock; + bool has_dom_bit = false; + + /* If we got a lock back and it has a LOOKUP bit set, + * make sure the dentry is marked as valid so we can find it. + * We don't need to care about actual hashing since other bits + * of kernel will deal with that later. + */ + lock = ldlm_handle2lock(&handle); + if (lock) { + has_dom_bit = ldlm_has_dom(lock); + if (lock->l_policy_data.l_inodebits.bits & + MDS_INODELOCK_LOOKUP) + d_lustre_revalidate(de); + + LDLM_LOCK_PUT(lock); + } ll_set_lock_data(sbi->ll_md_exp, de->d_inode, itp, NULL); + if (has_dom_bit) + ll_dom_finish_open(de->d_inode, req, itp); } out: @@ -786,6 +841,11 @@ restart: if (rc) GOTO(out_och_free, rc); } + + rc = pcc_file_open(inode, file); + if (rc) + GOTO(out_och_free, rc); + mutex_unlock(&lli->lli_och_mutex); fd = NULL; @@ -810,6 +870,7 @@ out_och_free: out_openerr: if (lli->lli_opendir_key == fd) ll_deauthorize_statahead(inode, fd); + if (fd != NULL) ll_file_data_put(fd); } else { @@ -1032,8 +1093,7 @@ out_close: rc2 = ll_close_inode_openhandle(inode, och, 0, NULL); if (rc2 < 0) CERROR("%s: error closing file "DFID": %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), - PFID(&ll_i2info(inode)->lli_fid), rc2); + sbi->ll_fsname, PFID(&ll_i2info(inode)->lli_fid), rc2); och = NULL; /* och has been freed in ll_close_inode_openhandle() */ out_release_it: ll_intent_release(&it); @@ -1077,7 +1137,7 @@ static int ll_swap_layouts_close(struct obd_client_handle *och, ENTRY; CDEBUG(D_INODE, "%s: biased close of file "DFID"\n", - ll_get_fsname(inode->i_sb, NULL, 0), PFID(fid1)); + ll_i2sbi(inode)->ll_fsname, PFID(fid1)); rc = ll_check_swap_layouts_validity(inode, inode2); if (rc < 0) @@ -1216,17 +1276,19 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode) * if it's at least 'mdd.*.atime_diff' older. * All in all, the atime in Lustre does not strictly comply with * POSIX. Solving this problem needs to send an RPC to MDT for each - * read, this will hurt performance. */ - if (LTIME_S(inode->i_atime) < lli->lli_atime || lli->lli_update_atime) { - LTIME_S(inode->i_atime) = lli->lli_atime; + * read, this will hurt performance. + */ + if (inode->i_atime.tv_sec < lli->lli_atime || + lli->lli_update_atime) { + inode->i_atime.tv_sec = lli->lli_atime; lli->lli_update_atime = 0; } - LTIME_S(inode->i_mtime) = lli->lli_mtime; - LTIME_S(inode->i_ctime) = lli->lli_ctime; + inode->i_mtime.tv_sec = lli->lli_mtime; + inode->i_ctime.tv_sec = lli->lli_ctime; - atime = LTIME_S(inode->i_atime); - mtime = LTIME_S(inode->i_mtime); - ctime = LTIME_S(inode->i_ctime); + mtime = inode->i_mtime.tv_sec; + atime = inode->i_atime.tv_sec; + ctime = inode->i_ctime.tv_sec; cl_object_attr_lock(obj); if (OBD_FAIL_CHECK(OBD_FAIL_MDC_MERGE)) @@ -1253,9 +1315,9 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode) i_size_write(inode, attr->cat_size); inode->i_blocks = attr->cat_blocks; - LTIME_S(inode->i_atime) = atime; - LTIME_S(inode->i_mtime) = mtime; - LTIME_S(inode->i_ctime) = ctime; + inode->i_mtime.tv_sec = mtime; + inode->i_atime.tv_sec = atime; + inode->i_ctime.tv_sec = ctime; out_size_unlock: ll_inode_size_unlock(inode); @@ -1310,13 +1372,13 @@ static bool file_is_noatime(const struct file *file) if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) return true; - if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) + if ((inode->i_sb->s_flags & SB_NODIRATIME) && S_ISDIR(inode->i_mode)) return true; return false; } -static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot) +void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot) { struct inode *inode = file_inode(file); struct ll_file_data *fd = LUSTRE_FPRIVATE(file); @@ -1339,6 +1401,7 @@ static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot) io->ci_lockreq = CILR_MANDATORY; } io->ci_noatime = file_is_noatime(file); + io->ci_async_readahead = false; /* FLR: only use non-delay I/O for read as there is only one * avaliable mirror for write. */ @@ -1347,6 +1410,37 @@ static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot) ll_io_set_mirror(io, file); } +static void ll_heat_add(struct inode *inode, enum cl_io_type iot, + __u64 count) +{ + struct ll_inode_info *lli = ll_i2info(inode); + struct ll_sb_info *sbi = ll_i2sbi(inode); + enum obd_heat_type sample_type; + enum obd_heat_type iobyte_type; + __u64 now = ktime_get_real_seconds(); + + if (!ll_sbi_has_file_heat(sbi) || + lli->lli_heat_flags & LU_HEAT_FLAG_OFF) + return; + + if (iot == CIT_READ) { + sample_type = OBD_HEAT_READSAMPLE; + iobyte_type = OBD_HEAT_READBYTE; + } else if (iot == CIT_WRITE) { + sample_type = OBD_HEAT_WRITESAMPLE; + iobyte_type = OBD_HEAT_WRITEBYTE; + } else { + return; + } + + spin_lock(&lli->lli_heat_lock); + obd_heat_add(&lli->lli_heat_instances[sample_type], now, 1, + sbi->ll_heat_decay_weight, sbi->ll_heat_period_second); + obd_heat_add(&lli->lli_heat_instances[iobyte_type], now, count, + sbi->ll_heat_decay_weight, sbi->ll_heat_period_second); + spin_unlock(&lli->lli_heat_lock); +} + static ssize_t ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args, struct file *file, enum cl_io_type iot, @@ -1477,6 +1571,8 @@ out: } CDEBUG(D_VFSTRACE, "iot: %d, result: %zd\n", iot, result); + if (result > 0) + ll_heat_add(inode, iot, result); RETURN(result > 0 ? result : rc); } @@ -1537,9 +1633,11 @@ ll_do_fast_read(struct kiocb *iocb, struct iov_iter *iter) if (result == -ENODATA) result = 0; - if (result > 0) + if (result > 0) { + ll_heat_add(file_inode(iocb->ki_filp), CIT_READ, result); ll_stats_ops_tally(ll_i2sbi(file_inode(iocb->ki_filp)), LPROC_LL_READ_BYTES, result); + } return result; } @@ -1554,6 +1652,27 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to) ssize_t result; ssize_t rc2; __u16 refcheck; + bool cached; + + if (!iov_iter_count(to)) + return 0; + + /** + * Currently when PCC read failed, we do not fall back to the + * normal read path, just return the error. + * The resaon is that: for RW-PCC, the file data may be modified + * in the PCC and inconsistent with the data on OSTs (or file + * data has been removed from the Lustre file system), at this + * time, fallback to the normal read path may read the wrong + * data. + * TODO: for RO-PCC (readonly PCC), fall back to normal read + * path: read data from data copy on OSTs. + */ + result = pcc_file_read_iter(iocb, to, &cached); + if (cached) + return result; + + ll_ras_enter(iocb->ki_filp); result = ll_do_fast_read(iocb, to); if (result < 0 || iov_iter_count(to) == 0) @@ -1599,8 +1718,9 @@ out: static ssize_t ll_do_tiny_write(struct kiocb *iocb, struct iov_iter *iter) { ssize_t count = iov_iter_count(iter); - struct file *file = iocb->ki_filp; - struct inode *inode = file_inode(file); + struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); + bool lock_inode = !IS_NOSEC(inode); ssize_t result = 0; ENTRY; @@ -1612,8 +1732,13 @@ static ssize_t ll_do_tiny_write(struct kiocb *iocb, struct iov_iter *iter) (iocb->ki_pos & (PAGE_SIZE-1)) + count > PAGE_SIZE) RETURN(0); + if (unlikely(lock_inode)) + inode_lock(inode); result = __generic_file_write_iter(iocb, iter); + if (unlikely(lock_inode)) + inode_unlock(inode); + /* If the page is not already dirty, ll_tiny_write_begin returns * -ENODATA. We continue on to normal write. */ @@ -1621,6 +1746,7 @@ static ssize_t ll_do_tiny_write(struct kiocb *iocb, struct iov_iter *iter) result = 0; if (result > 0) { + ll_heat_add(inode, CIT_WRITE, result); ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_WRITE_BYTES, result); ll_file_set_flag(ll_i2info(inode), LLIF_DATA_MODIFIED); @@ -1640,9 +1766,28 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from) struct lu_env *env; ssize_t rc_tiny = 0, rc_normal; __u16 refcheck; + bool cached; + int result; ENTRY; + if (!iov_iter_count(from)) + GOTO(out, rc_normal = 0); + + /** + * When PCC write failed, we usually do not fall back to the normal + * write path, just return the error. But there is a special case when + * returned error code is -ENOSPC due to running out of space on PCC HSM + * bakcend. At this time, it will fall back to normal I/O path and + * retry the I/O. As the file is in HSM released state, it will restore + * the file data to OSTs first and redo the write again. And the + * restore process will revoke the layout lock and detach the file + * from PCC cache automatically. + */ + result = pcc_file_write_iter(iocb, from, &cached); + if (cached && result != -ENOSPC && result != -EDQUOT) + return result; + /* NB: we can't do direct IO for tiny writes because they use the page * cache, we can't do sync writes because tiny writes can't flush * pages, and we can't do append writes because we can't guarantee the @@ -1727,6 +1872,9 @@ static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (result) RETURN(result); + if (!iov_count) + RETURN(0); + # ifdef HAVE_IOV_ITER_INIT_DIRECTION iov_iter_init(&to, READ, iov, nr_segs, iov_count); # else /* !HAVE_IOV_ITER_INIT_DIRECTION */ @@ -1744,8 +1892,12 @@ static ssize_t ll_file_read(struct file *file, char __user *buf, size_t count, struct iovec iov = { .iov_base = buf, .iov_len = count }; struct kiocb kiocb; ssize_t result; + ENTRY; + if (!count) + RETURN(0); + init_sync_kiocb(&kiocb, file); kiocb.ki_pos = *ppos; #ifdef HAVE_KIOCB_KI_LEFT @@ -1776,6 +1928,9 @@ static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (result) RETURN(result); + if (!iov_count) + RETURN(0); + # ifdef HAVE_IOV_ITER_INIT_DIRECTION iov_iter_init(&from, WRITE, iov, nr_segs, iov_count); # else /* !HAVE_IOV_ITER_INIT_DIRECTION */ @@ -1797,6 +1952,9 @@ static ssize_t ll_file_write(struct file *file, const char __user *buf, ENTRY; + if (!count) + RETURN(0); + init_sync_kiocb(&kiocb, file); kiocb.ki_pos = *ppos; #ifdef HAVE_KIOCB_KI_LEFT @@ -1819,13 +1977,22 @@ static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos, struct pipe_inode_info *pipe, size_t count, unsigned int flags) { - struct lu_env *env; - struct vvp_io_args *args; - ssize_t result; - __u16 refcheck; + struct lu_env *env; + struct vvp_io_args *args; + ssize_t result; + __u16 refcheck; + bool cached; + ENTRY; - env = cl_env_get(&refcheck); + result = pcc_file_splice_read(in_file, ppos, pipe, + count, flags, &cached); + if (cached) + RETURN(result); + + ll_ras_enter(in_file); + + env = cl_env_get(&refcheck); if (IS_ERR(env)) RETURN(PTR_ERR(env)); @@ -1907,7 +2074,8 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, if (lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V1) && lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V3) && - lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_COMP_V1)) + lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_COMP_V1) && + lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_FOREIGN)) GOTO(out, rc = -EPROTO); /* @@ -1946,6 +2114,15 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, cpu_to_le32(LOV_MAGIC_COMP_V1)) { lustre_swab_lov_comp_md_v1( (struct lov_comp_md_v1 *)lmm); + } else if (lmm->lmm_magic == + cpu_to_le32(LOV_MAGIC_FOREIGN)) { + struct lov_foreign_md *lfm; + + lfm = (struct lov_foreign_md *)lmm; + __swab32s(&lfm->lfm_magic); + __swab32s(&lfm->lfm_length); + __swab32s(&lfm->lfm_type); + __swab32s(&lfm->lfm_flags); } } @@ -2381,7 +2558,7 @@ int ll_hsm_release(struct inode *inode) ENTRY; CDEBUG(D_INODE, "%s: Releasing file "DFID".\n", - ll_get_fsname(inode->i_sb, NULL, 0), + ll_i2sbi(inode)->ll_fsname, PFID(&ll_i2info(inode)->lli_fid)); och = ll_lease_open(inode, NULL, FMODE_WRITE, MDS_OPEN_RELEASE); @@ -2789,6 +2966,7 @@ static const char *const ladvise_names[] = LU_LADVISE_NAMES; static int ll_ladvise_sanity(struct inode *inode, struct llapi_lu_ladvise *ladvise) { + struct ll_sb_info *sbi = ll_i2sbi(inode); enum lu_ladvise_type advice = ladvise->lla_advice; /* Note the peradvice flags is a 32 bit field, so per advice flags must * be in the first 32 bits of enum ladvise_flags */ @@ -2800,7 +2978,7 @@ static int ll_ladvise_sanity(struct inode *inode, rc = -EINVAL; CDEBUG(D_VFSTRACE, "%s: advice with value '%d' not recognized," "last supported advice is %s (value '%d'): rc = %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), advice, + sbi->ll_fsname, advice, ladvise_names[LU_LADVISE_MAX-1], LU_LADVISE_MAX-1, rc); GOTO(out, rc); } @@ -2811,8 +2989,7 @@ static int ll_ladvise_sanity(struct inode *inode, if (flags & ~LF_LOCKNOEXPAND_MASK) { rc = -EINVAL; CDEBUG(D_VFSTRACE, "%s: Invalid flags (%x) for %s: " - "rc = %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), flags, + "rc = %d\n", sbi->ll_fsname, flags, ladvise_names[advice], rc); GOTO(out, rc); } @@ -2823,8 +3000,7 @@ static int ll_ladvise_sanity(struct inode *inode, ladvise->lla_lockahead_mode == 0) { rc = -EINVAL; CDEBUG(D_VFSTRACE, "%s: Invalid mode (%d) for %s: " - "rc = %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), + "rc = %d\n", sbi->ll_fsname, ladvise->lla_lockahead_mode, ladvise_names[advice], rc); GOTO(out, rc); @@ -2837,16 +3013,14 @@ static int ll_ladvise_sanity(struct inode *inode, if (flags & ~LF_DEFAULT_MASK) { rc = -EINVAL; CDEBUG(D_VFSTRACE, "%s: Invalid flags (%x) for %s: " - "rc = %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), flags, + "rc = %d\n", sbi->ll_fsname, flags, ladvise_names[advice], rc); GOTO(out, rc); } if (ladvise->lla_start >= ladvise->lla_end) { rc = -EINVAL; CDEBUG(D_VFSTRACE, "%s: Invalid range (%llu to %llu) " - "for %s: rc = %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), + "for %s: rc = %d\n", sbi->ll_fsname, ladvise->lla_start, ladvise->lla_end, ladvise_names[advice], rc); GOTO(out, rc); @@ -3024,13 +3198,16 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, struct ll_inode_info *lli = ll_i2info(inode); struct obd_client_handle *och = NULL; struct split_param sp; - bool lease_broken; + struct pcc_param param; + bool lease_broken = false; fmode_t fmode = 0; enum mds_op_bias bias = 0; struct file *layout_file = NULL; void *data = NULL; size_t data_size = 0; - long rc; + bool attached = false; + long rc, rc2 = 0; + ENTRY; mutex_lock(&lli->lli_och_mutex); @@ -3041,22 +3218,22 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, mutex_unlock(&lli->lli_och_mutex); if (och == NULL) - GOTO(out, rc = -ENOLCK); + RETURN(-ENOLCK); fmode = och->och_flags; switch (ioc->lil_flags) { case LL_LEASE_RESYNC_DONE: if (ioc->lil_count > IOC_IDS_MAX) - GOTO(out, rc = -EINVAL); + GOTO(out_lease_close, rc = -EINVAL); data_size = offsetof(typeof(*ioc), lil_ids[ioc->lil_count]); OBD_ALLOC(data, data_size); if (!data) - GOTO(out, rc = -ENOMEM); + GOTO(out_lease_close, rc = -ENOMEM); if (copy_from_user(data, (void __user *)arg, data_size)) - GOTO(out, rc = -EFAULT); + GOTO(out_lease_close, rc = -EFAULT); bias = MDS_CLOSE_RESYNC_DONE; break; @@ -3064,19 +3241,19 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, int fd; if (ioc->lil_count != 1) - GOTO(out, rc = -EINVAL); + GOTO(out_lease_close, rc = -EINVAL); arg += sizeof(*ioc); if (copy_from_user(&fd, (void __user *)arg, sizeof(__u32))) - GOTO(out, rc = -EFAULT); + GOTO(out_lease_close, rc = -EFAULT); layout_file = fget(fd); if (!layout_file) - GOTO(out, rc = -EBADF); + GOTO(out_lease_close, rc = -EBADF); if ((file->f_flags & O_ACCMODE) == O_RDONLY || (layout_file->f_flags & O_ACCMODE) == O_RDONLY) - GOTO(out, rc = -EPERM); + GOTO(out_lease_close, rc = -EPERM); data = file_inode(layout_file); bias = MDS_CLOSE_LAYOUT_MERGE; @@ -3087,20 +3264,20 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, int mirror_id; if (ioc->lil_count != 2) - GOTO(out, rc = -EINVAL); + GOTO(out_lease_close, rc = -EINVAL); arg += sizeof(*ioc); if (copy_from_user(&fdv, (void __user *)arg, sizeof(__u32))) - GOTO(out, rc = -EFAULT); + GOTO(out_lease_close, rc = -EFAULT); arg += sizeof(__u32); if (copy_from_user(&mirror_id, (void __user *)arg, sizeof(__u32))) - GOTO(out, rc = -EFAULT); + GOTO(out_lease_close, rc = -EFAULT); layout_file = fget(fdv); if (!layout_file) - GOTO(out, rc = -EBADF); + GOTO(out_lease_close, rc = -EBADF); sp.sp_inode = file_inode(layout_file); sp.sp_mirror_id = (__u16)mirror_id; @@ -3108,11 +3285,35 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, bias = MDS_CLOSE_LAYOUT_SPLIT; break; } + case LL_LEASE_PCC_ATTACH: + if (ioc->lil_count != 1) + RETURN(-EINVAL); + + arg += sizeof(*ioc); + if (copy_from_user(¶m.pa_archive_id, (void __user *)arg, + sizeof(__u32))) + GOTO(out_lease_close, rc2 = -EFAULT); + + rc2 = pcc_readwrite_attach(file, inode, param.pa_archive_id); + if (rc2) + GOTO(out_lease_close, rc2); + + attached = true; + /* Grab latest data version */ + rc2 = ll_data_version(inode, ¶m.pa_data_version, + LL_DV_WR_FLUSH); + if (rc2) + GOTO(out_lease_close, rc2); + + data = ¶m; + bias = MDS_PCC_ATTACH; + break; default: /* without close intent */ break; } +out_lease_close: rc = ll_lease_close_intent(och, inode, &lease_broken, bias, data); if (rc < 0) GOTO(out, rc); @@ -3136,6 +3337,14 @@ out: if (layout_file) fput(layout_file); break; + case LL_LEASE_PCC_ATTACH: + if (!rc) + rc = rc2; + rc = pcc_readwrite_attach_fini(file, inode, + param.pa_layout_gen, + lease_broken, rc, + attached); + break; } if (!rc) @@ -3210,6 +3419,41 @@ static long ll_file_set_lease(struct file *file, struct ll_ioc_lease *ioc, RETURN(rc); } +static void ll_heat_get(struct inode *inode, struct lu_heat *heat) +{ + struct ll_inode_info *lli = ll_i2info(inode); + struct ll_sb_info *sbi = ll_i2sbi(inode); + __u64 now = ktime_get_real_seconds(); + int i; + + spin_lock(&lli->lli_heat_lock); + heat->lh_flags = lli->lli_heat_flags; + for (i = 0; i < heat->lh_count; i++) + heat->lh_heat[i] = obd_heat_get(&lli->lli_heat_instances[i], + now, sbi->ll_heat_decay_weight, + sbi->ll_heat_period_second); + spin_unlock(&lli->lli_heat_lock); +} + +static int ll_heat_set(struct inode *inode, enum lu_heat_flag flags) +{ + struct ll_inode_info *lli = ll_i2info(inode); + int rc = 0; + + spin_lock(&lli->lli_heat_lock); + if (flags & LU_HEAT_FLAG_CLEAR) + obd_heat_clear(lli->lli_heat_instances, OBD_HEAT_COUNT); + + if (flags & LU_HEAT_FLAG_OFF) + lli->lli_heat_flags |= LU_HEAT_FLAG_OFF; + else + lli->lli_heat_flags &= ~LU_HEAT_FLAG_OFF; + + spin_unlock(&lli->lli_heat_lock); + + RETURN(rc); +} + static long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -3593,6 +3837,83 @@ out_ladvise: RETURN(ll_ioctl_fssetxattr(inode, cmd, arg)); case BLKSSZGET: RETURN(put_user(PAGE_SIZE, (int __user *)arg)); + case LL_IOC_HEAT_GET: { + struct lu_heat uheat; + struct lu_heat *heat; + int size; + + if (copy_from_user(&uheat, (void __user *)arg, sizeof(uheat))) + RETURN(-EFAULT); + + if (uheat.lh_count > OBD_HEAT_COUNT) + uheat.lh_count = OBD_HEAT_COUNT; + + size = offsetof(typeof(uheat), lh_heat[uheat.lh_count]); + OBD_ALLOC(heat, size); + if (heat == NULL) + RETURN(-ENOMEM); + + heat->lh_count = uheat.lh_count; + ll_heat_get(inode, heat); + rc = copy_to_user((char __user *)arg, heat, size); + OBD_FREE(heat, size); + RETURN(rc ? -EFAULT : 0); + } + case LL_IOC_HEAT_SET: { + __u64 flags; + + if (copy_from_user(&flags, (void __user *)arg, sizeof(flags))) + RETURN(-EFAULT); + + rc = ll_heat_set(inode, flags); + RETURN(rc); + } + case LL_IOC_PCC_DETACH: { + struct lu_pcc_detach *detach; + + OBD_ALLOC_PTR(detach); + if (detach == NULL) + RETURN(-ENOMEM); + + if (copy_from_user(detach, + (const struct lu_pcc_detach __user *)arg, + sizeof(*detach))) + GOTO(out_detach_free, rc = -EFAULT); + + if (!S_ISREG(inode->i_mode)) + GOTO(out_detach_free, rc = -EINVAL); + + if (!inode_owner_or_capable(inode)) + GOTO(out_detach_free, rc = -EPERM); + + rc = pcc_ioctl_detach(inode, detach->pccd_opt); +out_detach_free: + OBD_FREE_PTR(detach); + RETURN(rc); + } + case LL_IOC_PCC_STATE: { + struct lu_pcc_state __user *ustate = + (struct lu_pcc_state __user *)arg; + struct lu_pcc_state *state; + + OBD_ALLOC_PTR(state); + if (state == NULL) + RETURN(-ENOMEM); + + if (copy_from_user(state, ustate, sizeof(*state))) + GOTO(out_state, rc = -EFAULT); + + rc = pcc_ioctl_state(file, inode, state); + if (rc) + GOTO(out_state, rc); + + if (copy_to_user(ustate, state, sizeof(*state))) + GOTO(out_state, rc = -EFAULT); + +out_state: + OBD_FREE_PTR(state); + RETURN(rc); + } default: RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL, (void __user *)arg)); @@ -3771,40 +4092,26 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end, * file_dentry() as is done otherwise. */ -#ifdef HAVE_FILE_FSYNC_4ARGS int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync) { struct dentry *dentry = file_dentry(file); -#elif defined(HAVE_FILE_FSYNC_2ARGS) -int ll_fsync(struct file *file, int datasync) -{ - struct dentry *dentry = file_dentry(file); - loff_t start = 0; - loff_t end = LLONG_MAX; -#else -int ll_fsync(struct file *file, struct dentry *dentry, int datasync) -{ - loff_t start = 0; - loff_t end = LLONG_MAX; -#endif struct inode *inode = dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); struct ptlrpc_request *req; int rc, err; + ENTRY; - CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", - PFID(ll_inode2fid(inode)), inode); + CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), start %lld, end %lld," + "datasync %d\n", + PFID(ll_inode2fid(inode)), inode, start, end, datasync); + ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FSYNC, 1); -#ifdef HAVE_FILE_FSYNC_4ARGS - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - inode_lock(inode); -#else /* fsync's caller has already called _fdata{sync,write}, we want * that IO to finish before calling the osc and mdc sync methods */ - rc = filemap_fdatawait(inode->i_mapping); -#endif + rc = filemap_write_and_wait_range(inode->i_mapping, start, end); + inode_lock(inode); /* catch async errors that were recorded back when async writeback * failed for pages in this mapping. */ @@ -3828,8 +4135,15 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) if (S_ISREG(inode->i_mode)) { struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + bool cached; - err = cl_sync_file_range(inode, start, end, CL_FSYNC_ALL, 0); + /* Sync metadata on MDT first, and then sync the cached data + * on PCC. + */ + err = pcc_fsync(file, start, end, datasync, &cached); + if (!cached) + err = cl_sync_file_range(inode, start, end, + CL_FSYNC_ALL, 0); if (rc == 0 && err < 0) rc = err; if (rc < 0) @@ -3838,9 +4152,7 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) fd->fd_write_failed = false; } -#ifdef HAVE_FILE_FSYNC_4ARGS inode_unlock(inode); -#endif RETURN(rc); } @@ -4069,10 +4381,9 @@ int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum, if (!(exp_connect_flags2(ll_i2sbi(parent)->ll_md_exp) & OBD_CONNECT2_DIR_MIGRATE)) { if (le32_to_cpu(lum->lum_stripe_count) > 1 || - ll_i2info(child_inode)->lli_lsm_md) { + ll_dir_striped(child_inode)) { CERROR("%s: MDT doesn't support stripe directory " - "migration!\n", - ll_get_fsname(parent->i_sb, NULL, 0)); + "migration!\n", ll_i2sbi(parent)->ll_fsname); GOTO(out_iput, rc = -EOPNOTSUPP); } } @@ -4094,7 +4405,7 @@ int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum, op_data->op_fid3 = *ll_inode2fid(child_inode); if (!fid_is_sane(&op_data->op_fid3)) { CERROR("%s: migrate %s, but FID "DFID" is insane\n", - ll_get_fsname(parent->i_sb, NULL, 0), name, + ll_i2sbi(parent)->ll_fsname, name, PFID(&op_data->op_fid3)); GOTO(out_unlock, rc = -EINVAL); } @@ -4132,7 +4443,9 @@ again: if (rc == 0) { LASSERT(request != NULL); ll_update_times(request, parent); + } + if (rc == 0 || rc == -EAGAIN) { body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY); LASSERT(body != NULL); @@ -4153,7 +4466,7 @@ again: request = NULL; } - /* Try again if the file layout has changed. */ + /* Try again if the lease has cancelled. */ if (rc == -EAGAIN && S_ISREG(child_inode->i_mode)) goto again; @@ -4173,9 +4486,20 @@ out_iput: static int ll_file_noflock(struct file *file, int cmd, struct file_lock *file_lock) { - ENTRY; + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + ENTRY; - RETURN(-ENOSYS); + /* + * In order to avoid flood of warning messages, only print one message + * for one file. And the entire message rate on the client is limited + * by CDEBUG_LIMIT too. + */ + if (!(fd->fd_flags & LL_FILE_FLOCK_WARNING)) { + fd->fd_flags |= LL_FILE_FLOCK_WARNING; + CDEBUG_LIMIT(D_TTY | D_CONSOLE, + "flock disabled, mount with '-o [local]flock' to enable\r\n"); + } + RETURN(-ENOSYS); } /** @@ -4207,7 +4531,7 @@ int ll_have_md_lock(struct inode *inode, __u64 *bits, enum ldlm_mode l_req_mode) ldlm_lockname[mode]); flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK; - for (i = 0; i <= MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) { + for (i = 0; i < MDS_INODELOCK_NUMBITS && *bits != 0; i++) { policy.l_inodebits.bits = *bits & (1 << i); if (policy.l_inodebits.bits == 0) continue; @@ -4255,8 +4579,7 @@ static int ll_inode_revalidate_fini(struct inode *inode, int rc) /* If it is striped directory, and there is bad stripe * Let's revalidate the dentry again, instead of returning * error */ - if (S_ISDIR(inode->i_mode) && - ll_i2info(inode)->lli_lsm_md != NULL) + if (ll_dir_striped(inode)) return 0; /* This path cannot be hit for regular files unless in @@ -4267,7 +4590,7 @@ static int ll_inode_revalidate_fini(struct inode *inode, int rc) } else if (rc != 0) { CDEBUG_LIMIT((rc == -EACCES || rc == -EIDRM) ? D_INFO : D_ERROR, "%s: revalidate FID "DFID" error: rc = %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), + ll_i2sbi(inode)->ll_fsname, PFID(ll_inode2fid(inode)), rc); } @@ -4332,6 +4655,10 @@ static int ll_merge_md_attr(struct inode *inode) int rc; LASSERT(lli->lli_lsm_md != NULL); + + if (!lmv_dir_striped(lli->lli_lsm_md)) + RETURN(0); + down_read(&lli->lli_lsm_sem); rc = md_merge_attr(ll_i2mdexp(inode), ll_i2info(inode)->lli_lsm_md, &attr, ll_md_blocking_ast); @@ -4350,27 +4677,8 @@ static int ll_merge_md_attr(struct inode *inode) RETURN(0); } -static inline dev_t ll_compat_encode_dev(dev_t dev) +int ll_getattr_dentry(struct dentry *de, struct kstat *stat) { - /* The compat_sys_*stat*() syscalls will fail unless the - * device majors and minors are both less than 256. Note that - * the value returned here will be passed through - * old_encode_dev() in cp_compat_stat(). And so we are not - * trying to return a valid compat (u16) device number, just - * one that will pass the old_valid_dev() check. */ - - return MKDEV(MAJOR(dev) & 0xff, MINOR(dev) & 0xff); -} - -#ifdef HAVE_INODEOPS_ENHANCED_GETATTR -int ll_getattr(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int flags) -{ - struct dentry *de = path->dentry; -#else -int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) -{ -#endif struct inode *inode = de->d_inode; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ll_inode_info *lli = ll_i2info(inode); @@ -4383,6 +4691,12 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) RETURN(rc); if (S_ISREG(inode->i_mode)) { + bool cached; + + rc = pcc_inode_getattr(inode, &cached); + if (cached && rc < 0) + RETURN(rc); + /* In case of restore, the MDT has the right size and has * already send it back without granting the layout lock, * inode is up-to-date so glimpse is useless. @@ -4390,23 +4704,22 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) * restore the MDT holds the layout lock so the glimpse will * block up to the end of restore (getattr will block) */ - if (!ll_file_test_flag(lli, LLIF_FILE_RESTORING)) { + if (!cached && !ll_file_test_flag(lli, LLIF_FILE_RESTORING)) { rc = ll_glimpse_size(inode); if (rc < 0) RETURN(rc); } } else { /* If object isn't regular a file then don't validate size. */ - if (S_ISDIR(inode->i_mode) && - lli->lli_lsm_md != NULL) { + if (ll_dir_striped(inode)) { rc = ll_merge_md_attr(inode); if (rc < 0) RETURN(rc); } - LTIME_S(inode->i_atime) = lli->lli_atime; - LTIME_S(inode->i_mtime) = lli->lli_mtime; - LTIME_S(inode->i_ctime) = lli->lli_ctime; + inode->i_atime.tv_sec = lli->lli_atime; + inode->i_mtime.tv_sec = lli->lli_mtime; + inode->i_ctime.tv_sec = lli->lli_ctime; } OBD_FAIL_TIMEOUT(OBD_FAIL_GETATTR_DELAY, 30); @@ -4436,6 +4749,18 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) return 0; } +#ifdef HAVE_INODEOPS_ENHANCED_GETATTR +int ll_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + struct dentry *de = path->dentry; +#else +int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) +{ +#endif + return ll_getattr_dentry(de, stat); +} + static int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) { @@ -4942,8 +5267,7 @@ out: /* wait for IO to complete if it's still being used. */ if (wait_layout) { CDEBUG(D_INODE, "%s: "DFID"(%p) wait for layout reconf\n", - ll_get_fsname(inode->i_sb, NULL, 0), - PFID(&lli->lli_fid), inode); + sbi->ll_fsname, PFID(&lli->lli_fid), inode); memset(&conf, 0, sizeof conf); conf.coc_opc = OBJECT_CONF_WAIT; @@ -4953,8 +5277,7 @@ out: rc = -EAGAIN; CDEBUG(D_INODE, "%s file="DFID" waiting layout return: %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), - PFID(&lli->lli_fid), rc); + sbi->ll_fsname, PFID(&lli->lli_fid), rc); } RETURN(rc); } @@ -4992,8 +5315,7 @@ static int ll_layout_intent(struct inode *inode, struct layout_intent *intent) it.it_flags = FMODE_WRITE; LDLM_DEBUG_NOLOCK("%s: requeue layout lock for file "DFID"(%p)", - ll_get_fsname(inode->i_sb, NULL, 0), - PFID(&lli->lli_fid), inode); + sbi->ll_fsname, PFID(&lli->lli_fid), inode); rc = md_intent_lock(sbi->ll_md_exp, op_data, &it, &req, &ll_md_blocking_ast, 0); @@ -5052,7 +5374,8 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen) /* mostly layout lock is caching on the local side, so try to * match it before grabbing layout lock mutex. */ mode = ll_take_md_lock(inode, MDS_INODELOCK_LAYOUT, &lockh, 0, - LCK_CR | LCK_CW | LCK_PR | LCK_PW); + LCK_CR | LCK_CW | LCK_PR | + LCK_PW | LCK_EX); if (mode != 0) { /* hit cached lock */ rc = ll_layout_lock_set(&lockh, mode, inode); if (rc == -EAGAIN)