+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct obd_client_handle *och = NULL;
+ struct split_param sp;
+ bool lease_broken;
+ 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;
+ ENTRY;
+
+ 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);
+
+ fmode = och->och_flags;
+
+ switch (ioc->lil_flags) {
+ case LL_LEASE_RESYNC_DONE:
+ if (ioc->lil_count > IOC_IDS_MAX)
+ GOTO(out, rc = -EINVAL);
+
+ data_size = offsetof(typeof(*ioc), lil_ids[ioc->lil_count]);
+ OBD_ALLOC(data, data_size);
+ if (!data)
+ GOTO(out, rc = -ENOMEM);
+
+ if (copy_from_user(data, (void __user *)arg, data_size))
+ GOTO(out, rc = -EFAULT);
+
+ bias = MDS_CLOSE_RESYNC_DONE;
+ break;
+ case LL_LEASE_LAYOUT_MERGE: {
+ int fd;
+
+ if (ioc->lil_count != 1)
+ GOTO(out, rc = -EINVAL);
+
+ arg += sizeof(*ioc);
+ if (copy_from_user(&fd, (void __user *)arg, sizeof(__u32)))
+ GOTO(out, rc = -EFAULT);
+
+ layout_file = fget(fd);
+ if (!layout_file)
+ GOTO(out, rc = -EBADF);
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY ||
+ (layout_file->f_flags & O_ACCMODE) == O_RDONLY)
+ GOTO(out, rc = -EPERM);
+
+ 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, rc = -EINVAL);
+
+ arg += sizeof(*ioc);
+ if (copy_from_user(&fdv, (void __user *)arg, sizeof(__u32)))
+ GOTO(out, rc = -EFAULT);
+
+ arg += sizeof(__u32);
+ if (copy_from_user(&mirror_id, (void __user *)arg,
+ sizeof(__u32)))
+ GOTO(out, rc = -EFAULT);
+
+ layout_file = fget(fdv);
+ if (!layout_file)
+ GOTO(out, rc = -EBADF);
+
+ sp.sp_inode = file_inode(layout_file);
+ sp.sp_mirror_id = (__u16)mirror_id;
+ data = &sp;
+ bias = MDS_CLOSE_LAYOUT_SPLIT;
+ break;
+ }
+ default:
+ /* without close intent */
+ break;
+ }
+
+ 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;
+ }
+
+ 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 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;