+ data = file_inode(layout_file);
+ bias = MDS_CLOSE_LAYOUT_MERGE;
+ break;
+ }
+ case LL_LEASE_LAYOUT_SPLIT: {
+ int fdv;
+ int mirror_id;
+
+ if (ioc->lil_count != 2)
+ GOTO(out_lease_close, rc = -EINVAL);
+
+ arg += sizeof(*ioc);
+ if (copy_from_user(&fdv, (void __user *)arg, sizeof(__u32)))
+ GOTO(out_lease_close, rc = -EFAULT);
+
+ arg += sizeof(__u32);
+ if (copy_from_user(&mirror_id, (void __user *)arg,
+ sizeof(__u32)))
+ GOTO(out_lease_close, rc = -EFAULT);
+
+ layout_file = fget(fdv);
+ if (!layout_file)
+ GOTO(out_lease_close, rc = -EBADF);
+
+ sp.sp_inode = file_inode(layout_file);
+ sp.sp_mirror_id = (__u16)mirror_id;
+ data = &sp;
+ 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);
+
+ rc = ll_lease_och_release(inode, file);
+ if (rc < 0)
+ GOTO(out, rc);
+
+ if (lease_broken)
+ fmode = 0;
+ EXIT;
+
+out:
+ switch (ioc->lil_flags) {
+ case LL_LEASE_RESYNC_DONE:
+ if (data)
+ OBD_FREE(data, data_size);
+ break;
+ case LL_LEASE_LAYOUT_MERGE:
+ case LL_LEASE_LAYOUT_SPLIT:
+ 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)
+ rc = ll_lease_type_from_fmode(fmode);
+ RETURN(rc);
+}
+
+static long ll_file_set_lease(struct file *file, struct ll_ioc_lease *ioc,
+ unsigned long arg)
+{
+ struct inode *inode = file_inode(file);
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+ struct obd_client_handle *och = NULL;
+ __u64 open_flags = 0;
+ bool lease_broken;
+ fmode_t fmode;
+ long rc;
+ ENTRY;
+
+ switch (ioc->lil_mode) {
+ case LL_LEASE_WRLCK:
+ if (!(file->f_mode & FMODE_WRITE))
+ RETURN(-EPERM);
+ fmode = FMODE_WRITE;
+ break;
+ case LL_LEASE_RDLCK:
+ if (!(file->f_mode & FMODE_READ))
+ RETURN(-EPERM);
+ fmode = FMODE_READ;
+ break;
+ case LL_LEASE_UNLCK:
+ RETURN(ll_file_unlock_lease(file, ioc, arg));
+ default:
+ RETURN(-EINVAL);
+ }
+
+ CDEBUG(D_INODE, "Set lease with mode %u\n", fmode);
+
+ /* apply for lease */
+ if (ioc->lil_flags & LL_LEASE_RESYNC)
+ open_flags = MDS_OPEN_RESYNC;
+ och = ll_lease_open(inode, file, fmode, open_flags);
+ if (IS_ERR(och))
+ RETURN(PTR_ERR(och));
+
+ if (ioc->lil_flags & LL_LEASE_RESYNC) {
+ rc = ll_lease_file_resync(och, inode, arg);
+ if (rc) {
+ ll_lease_close(och, inode, NULL);
+ RETURN(rc);
+ }
+ rc = ll_layout_refresh(inode, &fd->fd_layout_version);
+ if (rc) {
+ ll_lease_close(och, inode, NULL);
+ RETURN(rc);
+ }
+ }
+
+ rc = 0;
+ mutex_lock(&lli->lli_och_mutex);
+ if (fd->fd_lease_och == NULL) {
+ fd->fd_lease_och = och;
+ och = NULL;
+ }
+ mutex_unlock(&lli->lli_och_mutex);
+ if (och != NULL) {
+ /* impossible now that only excl is supported for now */
+ ll_lease_close(och, inode, &lease_broken);
+ rc = -EBUSY;
+ }
+ 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)
+{
+ struct inode *inode = file_inode(file);
+ struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
+ int flags, rc;
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), cmd=%x\n",
+ PFID(ll_inode2fid(inode)), inode, cmd);
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_IOCTL, 1);
+
+ /* asm-ppc{,64} declares TCGETS, et. al. as type 't' not 'T' */
+ if (_IOC_TYPE(cmd) == 'T' || _IOC_TYPE(cmd) == 't') /* tty ioctls */
+ RETURN(-ENOTTY);
+
+ switch (cmd) {
+ case LL_IOC_GETFLAGS:
+ /* Get the current value of the file flags */
+ return put_user(fd->fd_flags, (int __user *)arg);
+ case LL_IOC_SETFLAGS:
+ case LL_IOC_CLRFLAGS:
+ /* Set or clear specific file flags */
+ /* XXX This probably needs checks to ensure the flags are
+ * not abused, and to handle any flag side effects.
+ */
+ if (get_user(flags, (int __user *) arg))
+ RETURN(-EFAULT);
+
+ if (cmd == LL_IOC_SETFLAGS) {
+ if ((flags & LL_FILE_IGNORE_LOCK) &&
+ !(file->f_flags & O_DIRECT)) {
+ CERROR("%s: unable to disable locking on "
+ "non-O_DIRECT file\n", current->comm);
+ RETURN(-EINVAL);
+ }
+
+ fd->fd_flags |= flags;
+ } else {
+ fd->fd_flags &= ~flags;
+ }
+ RETURN(0);
+ case LL_IOC_LOV_SETSTRIPE:
+ case LL_IOC_LOV_SETSTRIPE_NEW:
+ RETURN(ll_lov_setstripe(inode, file, (void __user *)arg));
+ case LL_IOC_LOV_SETEA:
+ RETURN(ll_lov_setea(inode, file, (void __user *)arg));
+ case LL_IOC_LOV_SWAP_LAYOUTS: {
+ struct file *file2;
+ struct lustre_swap_layouts lsl;
+
+ if (copy_from_user(&lsl, (char __user *)arg,
+ sizeof(struct lustre_swap_layouts)))
+ RETURN(-EFAULT);
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ RETURN(-EPERM);
+
+ file2 = fget(lsl.sl_fd);
+ if (file2 == NULL)
+ RETURN(-EBADF);
+
+ /* O_WRONLY or O_RDWR */
+ if ((file2->f_flags & O_ACCMODE) == O_RDONLY)
+ GOTO(out, rc = -EPERM);
+
+ if (lsl.sl_flags & SWAP_LAYOUTS_CLOSE) {
+ struct inode *inode2;
+ struct ll_inode_info *lli;
+ struct obd_client_handle *och = NULL;
+
+ lli = ll_i2info(inode);
+ mutex_lock(&lli->lli_och_mutex);
+ if (fd->fd_lease_och != NULL) {
+ och = fd->fd_lease_och;
+ fd->fd_lease_och = NULL;
+ }
+ mutex_unlock(&lli->lli_och_mutex);
+ if (och == NULL)
+ GOTO(out, rc = -ENOLCK);
+ inode2 = file_inode(file2);
+ rc = ll_swap_layouts_close(och, inode, inode2);
+ } else {
+ rc = ll_swap_layouts(file, file2, &lsl);
+ }
+out:
+ fput(file2);
+ RETURN(rc);