Whamcloud - gitweb
LU-11595 mdt: fix read-on-open for big PAGE_SIZE
[fs/lustre-release.git] / lustre / llite / file.c
index 8bb2901..f866fba 100644 (file)
@@ -443,8 +443,26 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req,
        if (rnb == NULL || rnb->rnb_len == 0)
                RETURN_EXIT;
 
-       CDEBUG(D_INFO, "Get data buffer along with open, len %i, i_size %llu\n",
-              rnb->rnb_len, i_size_read(inode));
+       /* 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;
+
+       /* 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_get_fsname(inode->i_sb, NULL, 0), rnb->rnb_offset,
+                      rnb->rnb_len, i_size_read(inode));
+               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));
 
        data = (char *)rnb + sizeof(*rnb);
 
@@ -1137,10 +1155,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;
@@ -1150,6 +1169,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. */
@@ -1158,6 +1181,7 @@ static int ll_lease_file_resync(struct obd_client_handle *och,
                GOTO(out, rc);
 
        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);
@@ -3029,6 +3053,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)
 {
@@ -3041,20 +3089,20 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd,
        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_fsxattr, rc = -EFAULT);
-
        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)
@@ -3250,7 +3298,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);
@@ -4398,12 +4446,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);
 
@@ -4881,7 +4932,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;
@@ -4901,17 +4951,16 @@ 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)
+               RETURN(rc);
 
-       lmmsize = body->mbo_eadatasize;
+       lmmsize = rc;
+       rc = 0;
        if (lmmsize == 0) /* empty layout */
                GOTO(out, rc = 0);