X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Ffile.c;h=4d39246564680d58f91e24778e3f25293b869d81;hb=bc9cc327983c45e6255e0d6475b8bdbdcd82c938;hp=7a63adf4ebad724302f88d9a2414f87d05830a46;hpb=13372d6c243ccfc1a0886469f3c0dc048783ed47;p=fs%2Flustre-release.git diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 7a63adf..4d39246 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -99,12 +99,15 @@ static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data, op_data->op_attr.ia_mtime = inode->i_mtime; op_data->op_attr.ia_ctime = inode->i_ctime; op_data->op_attr.ia_size = i_size_read(inode); - op_data->op_attr.ia_valid |= ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET | - ATTR_MTIME | ATTR_MTIME_SET | - ATTR_CTIME | ATTR_CTIME_SET; + op_data->op_attr.ia_valid |= (ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET | + ATTR_MTIME | ATTR_MTIME_SET | + ATTR_CTIME); + op_data->op_xvalid |= OP_XVALID_CTIME_SET; op_data->op_attr_blocks = inode->i_blocks; op_data->op_attr_flags = ll_inode_to_ext_flags(inode->i_flags); - op_data->op_handle = och->och_fh; + if (ll_file_test_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT)) + op_data->op_attr_flags |= LUSTRE_PROJINHERIT_FL; + op_data->op_open_handle = och->och_open_handle; if (och->och_flags & FMODE_WRITE && ll_file_test_and_clear_flag(ll_i2info(inode), LLIF_DATA_MODIFIED)) @@ -136,8 +139,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); } @@ -152,7 +154,8 @@ static int ll_close_inode_openhandle(struct inode *inode, case MDS_CLOSE_LAYOUT_MERGE: /* merge blocks from the victim inode */ op_data->op_attr_blocks += ((struct inode *)data)->i_blocks; - op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS; + op_data->op_attr.ia_valid |= ATTR_SIZE; + op_data->op_xvalid |= OP_XVALID_BLOCKS; case MDS_CLOSE_LAYOUT_SPLIT: case MDS_CLOSE_LAYOUT_SWAP: { struct split_param *sp = data; @@ -176,7 +179,8 @@ static int ll_close_inode_openhandle(struct inode *inode, LASSERT(data != NULL); op_data->op_attr_blocks += ioc->lil_count * op_data->op_attr_blocks; - op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS; + op_data->op_attr.ia_valid |= ATTR_SIZE; + op_data->op_xvalid |= OP_XVALID_BLOCKS; op_data->op_bias |= MDS_CLOSE_RESYNC_DONE; op_data->op_lease_handle = och->och_lease_handle; @@ -191,7 +195,8 @@ static int ll_close_inode_openhandle(struct inode *inode, op_data->op_bias |= MDS_HSM_RELEASE; op_data->op_data_version = *(__u64 *)data; op_data->op_lease_handle = och->och_lease_handle; - op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS; + op_data->op_attr.ia_valid |= ATTR_SIZE; + op_data->op_xvalid |= OP_XVALID_BLOCKS; break; default: @@ -200,9 +205,9 @@ static int ll_close_inode_openhandle(struct inode *inode, } if (!(op_data->op_attr.ia_valid & ATTR_SIZE)) - op_data->op_attr.ia_valid |= MDS_ATTR_LSIZE; - if (!(op_data->op_attr.ia_valid & ATTR_BLOCKS)) - op_data->op_attr.ia_valid |= MDS_ATTR_LBLOCKS; + op_data->op_xvalid |= OP_XVALID_LAZYSIZE; + if (!(op_data->op_xvalid & OP_XVALID_BLOCKS)) + op_data->op_xvalid |= OP_XVALID_LAZYBLOCKS; rc = md_close(md_exp, op_data, och->och_mod, &req); if (rc != 0 && rc != -EINTR) @@ -222,7 +227,7 @@ static int ll_close_inode_openhandle(struct inode *inode, out: md_clear_open_replay_data(md_exp, och); - och->och_fh.cookie = DEAD_HANDLE_MAGIC; + och->och_open_handle.cookie = DEAD_HANDLE_MAGIC; OBD_FREE_PTR(och); ptlrpc_req_finished(req); /* This is close request */ @@ -408,14 +413,10 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req, struct page *vmpage; struct niobuf_remote *rnb; char *data; - struct lu_env *env; - struct cl_io *io; - __u16 refcheck; struct lustre_handle lockh; struct ldlm_lock *lock; unsigned long index, start; struct niobuf_local lnb; - int rc; bool dom_lock = false; ENTRY; @@ -430,33 +431,39 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req, dom_lock = ldlm_has_dom(lock); LDLM_LOCK_PUT(lock); } - if (!dom_lock) RETURN_EXIT; - env = cl_env_get(&refcheck); - if (IS_ERR(env)) - RETURN_EXIT; - if (!req_capsule_has_field(&req->rq_pill, &RMF_NIOBUF_INLINE, RCL_SERVER)) - GOTO(out_env, rc = -ENODATA); + RETURN_EXIT; rnb = req_capsule_server_get(&req->rq_pill, &RMF_NIOBUF_INLINE); - data = (char *)rnb + sizeof(*rnb); - if (rnb == NULL || rnb->rnb_len == 0) - GOTO(out_env, rc = 0); + RETURN_EXIT; + + /* LU-11595: Server may return whole file and that is OK always or + * it may return just file tail and its offset must be aligned with + * client PAGE_SIZE to be used on that client, if server's PAGE_SIZE is + * smaller then offset may be not aligned and that data is just ignored. + */ + if (rnb->rnb_offset % PAGE_SIZE) + RETURN_EXIT; - CDEBUG(D_INFO, "Get data buffer along with open, len %i, i_size %llu\n", - rnb->rnb_len, i_size_read(inode)); + /* Server returns whole file or just file tail if it fills in + * reply buffer, in both cases total size should be inode 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_i2sbi(inode)->ll_fsname, rnb->rnb_offset, + rnb->rnb_len, i_size_read(inode)); + RETURN_EXIT; + } - io = vvp_env_thread_io(env); - io->ci_obj = obj; - io->ci_ignore_layout = 1; - rc = cl_io_init(env, io, CIT_MISC, obj); - if (rc) - GOTO(out_io, rc); + 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)); + + data = (char *)rnb + sizeof(*rnb); lnb.lnb_file_offset = rnb->rnb_offset; start = lnb.lnb_file_offset / PAGE_SIZE; @@ -464,8 +471,6 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req, LASSERT(lnb.lnb_file_offset % PAGE_SIZE == 0); lnb.lnb_page_offset = 0; do { - struct cl_page *clp; - lnb.lnb_data = data + (index << PAGE_SHIFT); lnb.lnb_len = rnb->rnb_len - (index << PAGE_SHIFT); if (lnb.lnb_len > PAGE_SIZE) @@ -476,33 +481,15 @@ 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; } - lock_page(vmpage); - clp = cl_page_find(env, obj, vmpage->index, vmpage, - CPT_CACHEABLE); - if (IS_ERR(clp)) { - unlock_page(vmpage); - put_page(vmpage); - GOTO(out_io, rc = PTR_ERR(clp)); - } - - /* export page */ - cl_page_export(env, clp, 1); - cl_page_put(env, clp); - unlock_page(vmpage); put_page(vmpage); index++; } while (rnb->rnb_len > (index << PAGE_SHIFT)); - rc = 0; EXIT; -out_io: - cl_io_fini(env, io); -out_env: - cl_env_put(env, &refcheck); } static int ll_intent_file_open(struct dentry *de, void *lmm, int lmmsize, @@ -510,7 +497,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; @@ -522,21 +509,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 @@ -588,7 +597,7 @@ static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it, struct mdt_body *body; body = req_capsule_server_get(&it->it_request->rq_pill, &RMF_MDT_BODY); - och->och_fh = body->mbo_handle; + och->och_open_handle = body->mbo_open_handle; och->och_fid = body->mbo_fid1; och->och_lease_handle.cookie = it->it_lock_handle; och->och_magic = OBD_CLIENT_HANDLE_MAGIC; @@ -678,12 +687,13 @@ int ll_file_open(struct inode *inode, struct file *file) if (file->f_flags & O_TRUNC) oit.it_flags |= FMODE_WRITE; - /* kernel only call f_op->open in dentry_open. filp_open calls - * dentry_open after call to open_namei that checks permissions. - * Only nfsd_open call dentry_open directly without checking - * permissions and because of that this code below is safe. */ - if (oit.it_flags & (FMODE_WRITE | FMODE_READ)) - oit.it_flags |= MDS_OPEN_OWNEROVERRIDE; + /* kernel only call f_op->open in dentry_open. filp_open calls + * dentry_open after call to open_namei that checks permissions. + * Only nfsd_open call dentry_open directly without checking + * permissions and because of that this code below is safe. + */ + if (oit.it_flags & (FMODE_WRITE | FMODE_READ)) + oit.it_flags |= MDS_OPEN_OWNEROVERRIDE; /* We do not want O_EXCL here, presumably we opened the file * already? XXX - NFS implications? */ @@ -865,7 +875,7 @@ static int ll_md_blocking_lease_ast(struct ldlm_lock *lock, * if it has an open lock in cache already. */ static int ll_lease_och_acquire(struct inode *inode, struct file *file, - struct lustre_handle *old_handle) + struct lustre_handle *old_open_handle) { struct ll_inode_info *lli = ll_i2info(inode); struct ll_file_data *fd = LUSTRE_FPRIVATE(file); @@ -898,7 +908,7 @@ static int ll_lease_och_acquire(struct inode *inode, struct file *file, *och_p = NULL; } - *old_handle = fd->fd_och->och_fh; + *old_open_handle = fd->fd_och->och_open_handle; EXIT; out_unlock: @@ -959,7 +969,7 @@ ll_lease_open(struct inode *inode, struct file *file, fmode_t fmode, struct ll_sb_info *sbi = ll_i2sbi(inode); struct md_op_data *op_data; struct ptlrpc_request *req = NULL; - struct lustre_handle old_handle = { 0 }; + struct lustre_handle old_open_handle = { 0 }; struct obd_client_handle *och = NULL; int rc; int rc2; @@ -972,7 +982,7 @@ ll_lease_open(struct inode *inode, struct file *file, fmode_t fmode, if (!(fmode & file->f_mode) || (file->f_mode & FMODE_EXEC)) RETURN(ERR_PTR(-EPERM)); - rc = ll_lease_och_acquire(inode, file, &old_handle); + rc = ll_lease_och_acquire(inode, file, &old_open_handle); if (rc) RETURN(ERR_PTR(rc)); } @@ -987,7 +997,7 @@ ll_lease_open(struct inode *inode, struct file *file, fmode_t fmode, GOTO(out, rc = PTR_ERR(op_data)); /* To tell the MDT this openhandle is from the same owner */ - op_data->op_handle = old_handle; + op_data->op_open_handle = old_open_handle; it.it_flags = fmode | open_flags; it.it_flags |= MDS_OPEN_LOCK | MDS_OPEN_BY_FID | MDS_OPEN_LEASE; @@ -1043,8 +1053,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); @@ -1088,7 +1097,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) @@ -1166,10 +1175,11 @@ static int ll_lease_close(struct obd_client_handle *och, struct inode *inode, * After lease is taken, send the RPC MDS_REINT_RESYNC to the MDT */ static int ll_lease_file_resync(struct obd_client_handle *och, - struct inode *inode) + struct inode *inode, unsigned long arg) { struct ll_sb_info *sbi = ll_i2sbi(inode); struct md_op_data *op_data; + struct ll_ioc_lease_id ioc; __u64 data_version_unused; int rc; ENTRY; @@ -1179,6 +1189,10 @@ static int ll_lease_file_resync(struct obd_client_handle *och, if (IS_ERR(op_data)) RETURN(PTR_ERR(op_data)); + if (copy_from_user(&ioc, (struct ll_ioc_lease_id __user *)arg, + sizeof(ioc))) + RETURN(-EFAULT); + /* before starting file resync, it's necessary to clean up page cache * in client memory, otherwise once the layout version is increased, * writing back cached data will be denied the OSTs. */ @@ -1186,7 +1200,8 @@ static int ll_lease_file_resync(struct obd_client_handle *och, if (rc) GOTO(out, rc); - op_data->op_handle = och->och_lease_handle; + op_data->op_lease_handle = och->och_lease_handle; + op_data->op_mirror_id = ioc.lil_mirror_id; rc = md_file_resync(sbi->ll_md_exp, op_data); if (rc) GOTO(out, rc); @@ -1221,17 +1236,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)) @@ -1258,9 +1275,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); @@ -1288,8 +1305,6 @@ void ll_io_set_mirror(struct cl_io *io, const struct file *file) io->ci_ndelay = 0; io->ci_designated_mirror = fd->fd_designated_mirror; io->ci_layout_version = fd->fd_layout_version; - io->ci_pio = 0; /* doesn't have a mechanism to pass mirror - * io to ptasks */ } CDEBUG(D_VFSTRACE, "%s: desiginated mirror: %d\n", @@ -1323,23 +1338,17 @@ static bool file_is_noatime(const struct file *file) return false; } -static int ll_file_io_ptask(struct cfs_ptask *ptask); - static 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); - memset(&io->u.ci_rw.rw_iter, 0, sizeof(io->u.ci_rw.rw_iter)); - init_sync_kiocb(&io->u.ci_rw.rw_iocb, file); - io->u.ci_rw.rw_file = file; - io->u.ci_rw.rw_ptask = ll_file_io_ptask; - io->u.ci_rw.rw_nonblock = !!(file->f_flags & O_NONBLOCK); + io->u.ci_rw.crw_nonblock = file->f_flags & O_NONBLOCK; io->ci_lock_no_expand = fd->ll_lock_no_expand; if (iot == CIT_WRITE) { - io->u.ci_rw.rw_append = !!(file->f_flags & O_APPEND); - io->u.ci_rw.rw_sync = !!(file->f_flags & O_SYNC || + io->u.ci_wr.wr_append = !!(file->f_flags & O_APPEND); + io->u.ci_wr.wr_sync = !!(file->f_flags & O_SYNC || file->f_flags & O_DIRECT || IS_SYNC(inode)); } @@ -1352,10 +1361,6 @@ 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); - if (ll_i2sbi(inode)->ll_flags & LL_SBI_PIO) - io->ci_pio = !io->u.ci_rw.rw_append; - else - io->ci_pio = 0; /* FLR: only use non-delay I/O for read as there is only one * avaliable mirror for write. */ @@ -1364,77 +1369,35 @@ static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot) ll_io_set_mirror(io, file); } -static int ll_file_io_ptask(struct cfs_ptask *ptask) +static void ll_heat_add(struct inode *inode, enum cl_io_type iot, + __u64 count) { - struct cl_io_pt *pt = ptask->pt_cbdata; - struct file *file = pt->cip_file; - struct lu_env *env; - struct cl_io *io; - loff_t pos = pt->cip_pos; - int rc; - __u16 refcheck; - ENTRY; - - CDEBUG(D_VFSTRACE, "%s: %s range: [%llu, %llu)\n", - file_dentry(file)->d_name.name, - pt->cip_iot == CIT_READ ? "read" : "write", - pos, pos + pt->cip_count); - - env = cl_env_get(&refcheck); - if (IS_ERR(env)) - RETURN(PTR_ERR(env)); - - io = vvp_env_thread_io(env); - ll_io_init(io, file, pt->cip_iot); - io->u.ci_rw.rw_iter = pt->cip_iter; - io->u.ci_rw.rw_iocb = pt->cip_iocb; - io->ci_pio = 0; /* It's already in parallel task */ - - rc = cl_io_rw_init(env, io, pt->cip_iot, pos, - pt->cip_count - pt->cip_result); - if (!rc) { - struct vvp_io *vio = vvp_env_io(env); + 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(); - vio->vui_io_subtype = IO_NORMAL; - vio->vui_fd = LUSTRE_FPRIVATE(file); + if (!ll_sbi_has_file_heat(sbi) || + lli->lli_heat_flags & LU_HEAT_FLAG_OFF) + return; - ll_cl_add(file, env, io, LCC_RW); - rc = cl_io_loop(env, io); - ll_cl_remove(file, env); + 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 { - /* cl_io_rw_init() handled IO */ - rc = io->ci_result; - } - - if (OBD_FAIL_CHECK_RESET(OBD_FAIL_LLITE_PTASK_IO_FAIL, 0)) { - if (io->ci_nob > 0) - io->ci_nob /= 2; - rc = -EIO; + return; } - if (io->ci_nob > 0) { - pt->cip_result += io->ci_nob; - iov_iter_advance(&pt->cip_iter, io->ci_nob); - pos += io->ci_nob; - pt->cip_iocb.ki_pos = pos; -#ifdef HAVE_KIOCB_KI_LEFT - pt->cip_iocb.ki_left = pt->cip_count - pt->cip_result; -#elif defined(HAVE_KI_NBYTES) - pt->cip_iocb.ki_nbytes = pt->cip_count - pt->cip_result; -#endif - } - - cl_io_fini(env, io); - cl_env_put(env, &refcheck); - - pt->cip_need_restart = io->ci_need_restart; - - CDEBUG(D_VFSTRACE, "%s: %s ret: %zd, rc: %d\n", - file_dentry(file)->d_name.name, - pt->cip_iot == CIT_READ ? "read" : "write", - pt->cip_result, rc); - - RETURN(pt->cip_result > 0 ? 0 : rc); + 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 @@ -1442,13 +1405,12 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args, struct file *file, enum cl_io_type iot, loff_t *ppos, size_t count) { - struct range_lock range; struct vvp_io *vio = vvp_env_io(env); struct inode *inode = file_inode(file); struct ll_inode_info *lli = ll_i2info(inode); struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + struct range_lock range; struct cl_io *io; - loff_t pos = *ppos; ssize_t result = 0; int rc = 0; unsigned retried = 0; @@ -1456,34 +1418,30 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args, ENTRY; - CDEBUG(D_VFSTRACE, "%s: %s range: [%llu, %llu)\n", + CDEBUG(D_VFSTRACE, "%s: %s ppos: %llu, count: %zu\n", file_dentry(file)->d_name.name, - iot == CIT_READ ? "read" : "write", pos, pos + count); + iot == CIT_READ ? "read" : "write", *ppos, count); restart: io = vvp_env_thread_io(env); ll_io_init(io, file, iot); - if (args->via_io_subtype == IO_NORMAL) { - io->u.ci_rw.rw_iter = *args->u.normal.via_iter; - io->u.ci_rw.rw_iocb = *args->u.normal.via_iocb; - } - if (args->via_io_subtype != IO_NORMAL || restarted) - io->ci_pio = 0; io->ci_ndelay_tried = retried; - if (cl_io_rw_init(env, io, iot, pos, count) == 0) { + if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) { bool range_locked = false; if (file->f_flags & O_APPEND) range_lock_init(&range, 0, LUSTRE_EOF); else - range_lock_init(&range, pos, pos + count - 1); + range_lock_init(&range, *ppos, *ppos + count - 1); vio->vui_fd = LUSTRE_FPRIVATE(file); vio->vui_io_subtype = args->via_io_subtype; switch (vio->vui_io_subtype) { case IO_NORMAL: + vio->vui_iter = args->u.normal.via_iter; + vio->vui_iocb = args->u.normal.via_iocb; /* Direct IO reads must also take range lock, * or multiple reads will try to work on the same pages * See LU-6227 for details. */ @@ -1509,16 +1467,7 @@ restart: } ll_cl_add(file, env, io, LCC_RW); - if (io->ci_pio && iot == CIT_WRITE && !IS_NOSEC(inode) && - !lli->lli_inode_locked) { - inode_lock(inode); - lli->lli_inode_locked = 1; - } rc = cl_io_loop(env, io); - if (lli->lli_inode_locked) { - lli->lli_inode_locked = 0; - inode_unlock(inode); - } ll_cl_remove(file, env); if (range_locked) { @@ -1534,26 +1483,11 @@ restart: if (io->ci_nob > 0) { result += io->ci_nob; count -= io->ci_nob; + *ppos = io->u.ci_wr.wr.crw_pos; /* for splice */ - if (args->via_io_subtype == IO_NORMAL) { - iov_iter_advance(args->u.normal.via_iter, io->ci_nob); - - /* CLIO is too complicated. See LU-11069. */ - if (cl_io_is_append(io)) - pos = io->u.ci_rw.rw_iocb.ki_pos; - else - pos += io->ci_nob; - - args->u.normal.via_iocb->ki_pos = pos; -#ifdef HAVE_KIOCB_KI_LEFT - args->u.normal.via_iocb->ki_left = count; -#elif defined(HAVE_KI_NBYTES) - args->u.normal.via_iocb->ki_nbytes = count; -#endif - } else { - /* for splice */ - pos = io->u.ci_rw.rw_range.cir_pos; - } + /* prepare IO restart */ + if (count > 0 && args->via_io_subtype == IO_NORMAL) + args->u.normal.via_iter = vio->vui_iter; } out: cl_io_fini(env, io); @@ -1565,10 +1499,10 @@ out: if ((rc == 0 || rc == -ENODATA) && count > 0 && io->ci_need_restart) { CDEBUG(D_VFSTRACE, - "%s: restart %s range: [%llu, %llu) ret: %zd, rc: %d\n", - file_dentry(file)->d_name.name, - iot == CIT_READ ? "read" : "write", - pos, pos + count, result, rc); + "%s: restart %s from %lld, count: %zu, ret: %zd, rc: %d\n", + file_dentry(file)->d_name.name, + iot == CIT_READ ? "read" : "write", + *ppos, count, result, rc); /* preserve the tried count for FLR */ retried = io->ci_ndelay_tried; restarted = true; @@ -1595,11 +1529,9 @@ out: } } - CDEBUG(D_VFSTRACE, "%s: %s *ppos: %llu, pos: %llu, ret: %zd, rc: %d\n", - file_dentry(file)->d_name.name, - iot == CIT_READ ? "read" : "write", *ppos, pos, result, rc); - - *ppos = pos; + CDEBUG(D_VFSTRACE, "iot: %d, result: %zd\n", iot, result); + if (result > 0) + ll_heat_add(inode, iot, result); RETURN(result > 0 ? result : rc); } @@ -1660,9 +1592,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; } @@ -1722,8 +1656,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; @@ -1735,8 +1670,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. */ @@ -1744,6 +1684,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); @@ -2504,7 +2445,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); @@ -2661,8 +2602,9 @@ free: int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss) { - struct md_op_data *op_data; - int rc; + struct obd_export *exp = ll_i2mdexp(inode); + struct md_op_data *op_data; + int rc; ENTRY; /* Detect out-of range masks */ @@ -2675,18 +2617,20 @@ int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss) !cfs_capable(CFS_CAP_SYS_ADMIN)) RETURN(-EPERM); - /* Detect out-of range archive id */ - if ((hss->hss_valid & HSS_ARCHIVE_ID) && - (hss->hss_archive_id > LL_HSM_MAX_ARCHIVE)) - RETURN(-EINVAL); + if (!exp_connect_archive_id_array(exp)) { + /* Detect out-of range archive id */ + if ((hss->hss_valid & HSS_ARCHIVE_ID) && + (hss->hss_archive_id > LL_HSM_ORIGIN_MAX_ARCHIVE)) + RETURN(-EINVAL); + } op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, LUSTRE_OPC_ANY, hss); if (IS_ERR(op_data)) RETURN(PTR_ERR(op_data)); - rc = obd_iocontrol(LL_IOC_HSM_STATE_SET, ll_i2mdexp(inode), - sizeof(*op_data), op_data, NULL); + rc = obd_iocontrol(LL_IOC_HSM_STATE_SET, exp, sizeof(*op_data), + op_data, NULL); ll_finish_md_op_data(op_data); @@ -2737,7 +2681,7 @@ static int ll_hsm_import(struct inode *inode, struct file *file, inode_lock(inode); - rc = ll_setattr_raw(file_dentry(file), attr, true); + rc = ll_setattr_raw(file_dentry(file), attr, 0, true); if (rc == -ENODATA) rc = 0; @@ -2765,7 +2709,7 @@ static int ll_file_futimes_3(struct file *file, const struct ll_futimes_3 *lfu) struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_ATIME_SET | ATTR_MTIME | ATTR_MTIME_SET | - ATTR_CTIME | ATTR_CTIME_SET, + ATTR_CTIME, .ia_atime = { .tv_sec = lfu->lfu_atime_sec, .tv_nsec = lfu->lfu_atime_nsec, @@ -2789,7 +2733,8 @@ static int ll_file_futimes_3(struct file *file, const struct ll_futimes_3 *lfu) RETURN(-EINVAL); inode_lock(inode); - rc = ll_setattr_raw(file_dentry(file), &ia, false); + rc = ll_setattr_raw(file_dentry(file), &ia, OP_XVALID_CTIME_SET, + false); inode_unlock(inode); RETURN(rc); @@ -2908,6 +2853,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 */ @@ -2919,7 +2865,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); } @@ -2930,8 +2876,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); } @@ -2942,8 +2887,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); @@ -2956,16 +2900,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); @@ -3046,7 +2988,9 @@ int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd, sizeof(fsxattr))) RETURN(-EFAULT); - fsxattr.fsx_xflags = ll_inode_to_ext_flags(inode->i_flags); + fsxattr.fsx_xflags = ll_inode_flags_to_xflags(inode->i_flags); + if (ll_file_test_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT)) + fsxattr.fsx_xflags |= FS_XFLAG_PROJINHERIT; fsxattr.fsx_projid = ll_i2info(inode)->lli_projid; if (copy_to_user((struct fsxattr __user *)arg, &fsxattr, sizeof(fsxattr))) @@ -3055,6 +2999,30 @@ int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd, RETURN(0); } +int ll_ioctl_check_project(struct inode *inode, struct fsxattr *fa) +{ + /* + * Project Quota ID state is only allowed to change from within the init + * namespace. Enforce that restriction only if we are trying to change + * the quota ID state. Everything else is allowed in user namespaces. + */ + if (current_user_ns() == &init_user_ns) + return 0; + + if (ll_i2info(inode)->lli_projid != fa->fsx_projid) + return -EINVAL; + + if (ll_file_test_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT)) { + if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT)) + return -EINVAL; + } else { + if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT) + return -EINVAL; + } + + return 0; +} + int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, unsigned long arg) { @@ -3064,42 +3032,47 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, int rc = 0; struct fsxattr fsxattr; struct cl_object *obj; + struct iattr *attr; + int flags; - /* only root could change project ID */ - if (!cfs_capable(CFS_CAP_SYS_ADMIN)) - RETURN(-EPERM); + if (copy_from_user(&fsxattr, + (const struct fsxattr __user *)arg, + sizeof(fsxattr))) + RETURN(-EFAULT); + + rc = ll_ioctl_check_project(inode, &fsxattr); + if (rc) + RETURN(rc); op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, LUSTRE_OPC_ANY, NULL); if (IS_ERR(op_data)) RETURN(PTR_ERR(op_data)); - if (copy_from_user(&fsxattr, - (const struct fsxattr __user *)arg, - sizeof(fsxattr))) - GOTO(out_fsxattr1, rc = -EFAULT); - - op_data->op_attr_flags = fsxattr.fsx_xflags; + flags = ll_xflags_to_inode_flags(fsxattr.fsx_xflags); + op_data->op_attr_flags = ll_inode_to_ext_flags(flags); + if (fsxattr.fsx_xflags & FS_XFLAG_PROJINHERIT) + op_data->op_attr_flags |= LUSTRE_PROJINHERIT_FL; op_data->op_projid = fsxattr.fsx_projid; - op_data->op_attr.ia_valid |= (MDS_ATTR_PROJID | ATTR_ATTR_FLAG); + op_data->op_xvalid |= OP_XVALID_PROJID | OP_XVALID_FLAGS; rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, op_data, NULL, 0, &req); ptlrpc_req_finished(req); - + if (rc) + GOTO(out_fsxattr, rc); + ll_update_inode_flags(inode, op_data->op_attr_flags); obj = ll_i2info(inode)->lli_clob; - if (obj) { - struct iattr *attr; + if (obj == NULL) + GOTO(out_fsxattr, rc); - inode->i_flags = ll_ext_to_inode_flags(fsxattr.fsx_xflags); - OBD_ALLOC_PTR(attr); - if (attr == NULL) - GOTO(out_fsxattr1, rc = -ENOMEM); - attr->ia_valid = ATTR_ATTR_FLAG; - rc = cl_setattr_ost(obj, attr, fsxattr.fsx_xflags); + OBD_ALLOC_PTR(attr); + if (attr == NULL) + GOTO(out_fsxattr, rc = -ENOMEM); - OBD_FREE_PTR(attr); - } -out_fsxattr1: + rc = cl_setattr_ost(obj, attr, OP_XVALID_FLAGS, + fsxattr.fsx_xflags); + OBD_FREE_PTR(attr); +out_fsxattr: ll_finish_md_op_data(op_data); RETURN(rc); } @@ -3271,7 +3244,7 @@ static long ll_file_set_lease(struct file *file, struct ll_ioc_lease *ioc, RETURN(PTR_ERR(och)); if (ioc->lil_flags & LL_LEASE_RESYNC) { - rc = ll_lease_file_resync(och, inode); + rc = ll_lease_file_resync(och, inode, arg); if (rc) { ll_lease_close(och, inode, NULL); RETURN(rc); @@ -3298,6 +3271,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, __u64 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) { @@ -3681,6 +3689,37 @@ 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); + } default: RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL, (void __user *)arg)); @@ -3863,7 +3902,6 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end, int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync) { struct dentry *dentry = file_dentry(file); - bool lock_inode; #elif defined(HAVE_FILE_FSYNC_2ARGS) int ll_fsync(struct file *file, int datasync) { @@ -3888,9 +3926,7 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) #ifdef HAVE_FILE_FSYNC_4ARGS rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - lock_inode = !lli->lli_inode_locked; - if (lock_inode) - inode_lock(inode); + 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 */ @@ -3930,8 +3966,7 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) } #ifdef HAVE_FILE_FSYNC_4ARGS - if (lock_inode) - inode_unlock(inode); + inode_unlock(inode); #endif RETURN(rc); } @@ -4113,48 +4148,60 @@ out_req: RETURN(rc); } -int ll_migrate(struct inode *parent, struct file *file, int mdtidx, - const char *name, int namelen) +int ll_migrate(struct inode *parent, struct file *file, struct lmv_user_md *lum, + const char *name) { - struct dentry *dchild = NULL; - struct inode *child_inode = NULL; - struct md_op_data *op_data; + struct dentry *dchild = NULL; + struct inode *child_inode = NULL; + struct md_op_data *op_data; struct ptlrpc_request *request = NULL; struct obd_client_handle *och = NULL; - struct qstr qstr; - struct mdt_body *body; - int rc; - __u64 data_version = 0; + struct qstr qstr; + struct mdt_body *body; + __u64 data_version = 0; + size_t namelen = strlen(name); + int lumlen = lmv_user_md_size(lum->lum_stripe_count, lum->lum_magic); + int rc; ENTRY; - CDEBUG(D_VFSTRACE, "migrate %s under "DFID" to MDT%04x\n", - name, PFID(ll_inode2fid(parent)), mdtidx); + CDEBUG(D_VFSTRACE, "migrate "DFID"/%s to MDT%04x stripe count %d\n", + PFID(ll_inode2fid(parent)), name, + lum->lum_stripe_offset, lum->lum_stripe_count); - op_data = ll_prep_md_op_data(NULL, parent, NULL, name, namelen, - 0, LUSTRE_OPC_ANY, NULL); - if (IS_ERR(op_data)) - RETURN(PTR_ERR(op_data)); + if (lum->lum_magic != cpu_to_le32(LMV_USER_MAGIC) && + lum->lum_magic != cpu_to_le32(LMV_USER_MAGIC_SPECIFIC)) + lustre_swab_lmv_user_md(lum); /* Get child FID first */ qstr.hash = ll_full_name_hash(file_dentry(file), name, namelen); qstr.name = name; qstr.len = namelen; dchild = d_lookup(file_dentry(file), &qstr); - if (dchild != NULL) { - if (dchild->d_inode != NULL) + if (dchild) { + if (dchild->d_inode) child_inode = igrab(dchild->d_inode); dput(dchild); } - if (child_inode == NULL) { - rc = ll_get_fid_by_name(parent, name, namelen, - &op_data->op_fid3, &child_inode); - if (rc != 0) - GOTO(out_free, rc); + if (!child_inode) { + rc = ll_get_fid_by_name(parent, name, namelen, NULL, + &child_inode); + if (rc) + RETURN(rc); } - if (child_inode == NULL) - GOTO(out_free, rc = -EINVAL); + if (!child_inode) + RETURN(-ENOENT); + + 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) { + CERROR("%s: MDT doesn't support stripe directory " + "migration!\n", ll_i2sbi(parent)->ll_fsname); + GOTO(out_iput, rc = -EOPNOTSUPP); + } + } /* * lfs migrate command needs to be blocked on the client @@ -4164,24 +4211,24 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx, if (child_inode == parent->i_sb->s_root->d_inode) GOTO(out_iput, rc = -EINVAL); + op_data = ll_prep_md_op_data(NULL, parent, NULL, name, namelen, + child_inode->i_mode, LUSTRE_OPC_ANY, NULL); + if (IS_ERR(op_data)) + GOTO(out_iput, rc = PTR_ERR(op_data)); + inode_lock(child_inode); 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); } - rc = ll_get_mdt_idx_by_fid(ll_i2sbi(parent), &op_data->op_fid3); - if (rc < 0) - GOTO(out_unlock, rc); + op_data->op_cli_flags |= CLI_MIGRATE | CLI_SET_MEA; + op_data->op_data = lum; + op_data->op_data_size = lumlen; - if (rc == mdtidx) { - CDEBUG(D_INFO, "%s: "DFID" is already on MDT%04x\n", name, - PFID(&op_data->op_fid3), mdtidx); - GOTO(out_unlock, rc = 0); - } again: if (S_ISREG(child_inode->i_mode)) { och = ll_lease_open(child_inode, NULL, FMODE_WRITE, 0); @@ -4196,32 +4243,34 @@ again: if (rc != 0) GOTO(out_close, rc); - op_data->op_handle = och->och_fh; - op_data->op_data = och->och_mod; + op_data->op_open_handle = och->och_open_handle; op_data->op_data_version = data_version; op_data->op_lease_handle = och->och_lease_handle; - op_data->op_bias |= MDS_RENAME_MIGRATE; + op_data->op_bias |= MDS_CLOSE_MIGRATE; + + spin_lock(&och->och_mod->mod_open_req->rq_lock); + och->och_mod->mod_open_req->rq_replay = 0; + spin_unlock(&och->och_mod->mod_open_req->rq_lock); } - op_data->op_mds = mdtidx; - op_data->op_cli_flags = CLI_MIGRATE; - rc = md_rename(ll_i2sbi(parent)->ll_md_exp, op_data, name, - namelen, name, namelen, &request); + rc = md_rename(ll_i2sbi(parent)->ll_md_exp, op_data, name, namelen, + name, namelen, &request); 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); /* If the server does release layout lock, then we cleanup * the client och here, otherwise release it in out_close: */ - if (och != NULL && - body->mbo_valid & OBD_MD_CLOSE_INTENT_EXECED) { + if (och && body->mbo_valid & OBD_MD_CLOSE_INTENT_EXECED) { obd_mod_put(och->och_mod); md_clear_open_replay_data(ll_i2sbi(parent)->ll_md_exp, och); - och->och_fh.cookie = DEAD_HANDLE_MAGIC; + och->och_open_handle.cookie = DEAD_HANDLE_MAGIC; OBD_FREE_PTR(och); och = NULL; } @@ -4232,21 +4281,20 @@ 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; out_close: - if (och != NULL) /* close the file */ + if (och) ll_lease_close(och, child_inode, NULL); - if (rc == 0) + if (!rc) clear_nlink(child_inode); out_unlock: inode_unlock(child_inode); + ll_finish_md_op_data(op_data); out_iput: iput(child_inode); -out_free: - ll_finish_md_op_data(op_data); RETURN(rc); } @@ -4347,7 +4395,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); } @@ -4407,12 +4455,15 @@ out: static int ll_merge_md_attr(struct inode *inode) { + struct ll_inode_info *lli = ll_i2info(inode); struct cl_attr attr = { 0 }; int rc; - LASSERT(ll_i2info(inode)->lli_lsm_md != NULL); + LASSERT(lli->lli_lsm_md != NULL); + down_read(&lli->lli_lsm_sem); rc = md_merge_attr(ll_i2mdexp(inode), ll_i2info(inode)->lli_lsm_md, &attr, ll_md_blocking_ast); + up_read(&lli->lli_lsm_sem); if (rc != 0) RETURN(rc); @@ -4481,9 +4532,9 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) 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); @@ -4890,7 +4941,6 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) { struct ll_sb_info *sbi = ll_i2sbi(inode); struct ptlrpc_request *req; - struct mdt_body *body; void *lvbdata; void *lmm; int lmmsize; @@ -4910,17 +4960,20 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) * layout here. Please note that we can't use the LVB buffer in * completion AST because it doesn't have a large enough buffer */ rc = ll_get_default_mdsize(sbi, &lmmsize); - if (rc == 0) - rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), - OBD_MD_FLXATTR, XATTR_NAME_LOV, lmmsize, &req); if (rc < 0) RETURN(rc); - body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); - if (body == NULL) - GOTO(out, rc = -EPROTO); + rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), OBD_MD_FLXATTR, + XATTR_NAME_LOV, lmmsize, &req); + if (rc < 0) { + if (rc == -ENODATA) + GOTO(out, rc = 0); /* empty layout */ + else + RETURN(rc); + } - lmmsize = body->mbo_eadatasize; + lmmsize = rc; + rc = 0; if (lmmsize == 0) /* empty layout */ GOTO(out, rc = 0); @@ -5017,8 +5070,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; @@ -5028,8 +5080,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); } @@ -5067,8 +5118,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);