+static int mds_extent_lock_callback(struct ldlm_lock *lock,
+ struct ldlm_lock_desc *new, void *data,
+ int flag)
+{
+ struct lustre_handle lockh = { 0 };
+ int rc;
+ ENTRY;
+
+ switch (flag) {
+ case LDLM_CB_BLOCKING:
+ ldlm_lock2handle(lock, &lockh);
+ rc = ldlm_cli_cancel(&lockh);
+ if (rc != ELDLM_OK)
+ CERROR("ldlm_cli_cancel failed: %d\n", rc);
+ break;
+ case LDLM_CB_CANCELING: {
+ break;
+ }
+ default:
+ LBUG();
+ }
+
+ RETURN(0);
+}
+__u64 lov_merge_size(struct lov_stripe_md *lsm, int kms);
+__u64 lov_merge_blocks(struct lov_stripe_md *lsm);
+__u64 lov_merge_mtime(struct lov_stripe_md *lsm, __u64 current_time);
+
+int mds_validate_size(struct obd_device *obd, struct inode *inode,
+ struct mds_body *body, struct iattr *iattr)
+{
+ ldlm_policy_data_t policy = { .l_extent = { 0, OBD_OBJECT_EOF } };
+ struct lustre_handle lockh = { 0 };
+ struct lov_stripe_md *lsm = NULL;
+ int rc, len, flags;
+ void *lmm = NULL;
+ ENTRY;
+
+ /* we update i_size/i_blocks only for regular files */
+ if (!S_ISREG(inode->i_mode))
+ RETURN(0);
+
+ /* we shouldn't fetch size from OSTes during recovery - deadlock */
+ if (obd->obd_recovering) {
+ CERROR("size-on-mds has no support on OST yet\n");
+ RETURN(0);
+ }
+
+ /* if nobody modified attrs. we're lucky */
+ if (!mds_inode_has_old_attrs(inode))
+ RETURN(0);
+
+ /* 1: client didn't send actual i_size/i_blocks
+ * 2: we seem to be last writer
+ * 3: the file doesn't look like to be disappeared
+ * conclusion: we're gonna fetch them from OSSes */
+
+ down(&inode->i_sem);
+ len = fsfilt_get_md(obd, inode, NULL, 0, EA_LOV);
+ up(&inode->i_sem);
+
+ if (len < 0) {
+ CERROR("error getting inode %lu MD: %d\n", inode->i_ino, len);
+ GOTO(cleanup, rc = len);
+ } else if (len == 0) {
+ CDEBUG(D_INODE, "no LOV in inode %lu\n", inode->i_ino);
+ GOTO(cleanup, rc = 0);
+ }
+
+ OBD_ALLOC(lmm, len);
+ if (lmm == NULL) {
+ CERROR("can't allocate memory\n");
+ GOTO(cleanup, rc = -ENOMEM);
+ }
+
+ down(&inode->i_sem);
+ rc = fsfilt_get_md(obd, inode, lmm, len, EA_LOV);
+ up(&inode->i_sem);
+
+ if (rc < 0) {
+ CERROR("error getting inode %lu MD: %d\n", inode->i_ino, rc);
+ GOTO(cleanup, rc);
+ }
+
+ rc = obd_unpackmd(obd->u.mds.mds_dt_exp, &lsm, lmm, len);
+ if (rc < 0) {
+ CERROR("error getting inode %lu MD: %d\n", inode->i_ino, rc);
+ GOTO(cleanup, rc);
+ }
+
+ CDEBUG(D_DLMTRACE, "Glimpsing inode %lu\n", inode->i_ino);
+
+ flags = LDLM_FL_HAS_INTENT;
+ rc = obd_enqueue(obd->u.mds.mds_dt_exp, lsm, LDLM_EXTENT, &policy,
+ LCK_PR, &flags, mds_extent_lock_callback,
+ ldlm_completion_ast, NULL, NULL,
+ sizeof(struct ost_lvb), lustre_swab_ost_lvb, &lockh);
+ if (rc == -ENOENT) {
+ /* while we were enqueueing lock on OST, another thread
+ * unlinked the file and started OST object destoying.
+ * it's safe to return 0 here */
+ GOTO(cleanup, rc = 0);
+ } else if (rc != 0) {
+ CERROR("obd_enqueue returned rc %d, returning -EIO\n", rc);
+ GOTO(cleanup, rc);
+ }
+
+ CDEBUG(D_INODE, "LOV reports "LPD64"/%lu for "DLID4" [%s%s%s]\n",
+ inode->i_size, inode->i_blocks, OLID4(&body->id1),
+ atomic_read(&inode->i_writecount) > 1 ? "U" : "",
+ mds_inode_has_old_attrs(inode) ? "D" : "",
+ mds_inode_is_orphan(inode) ? "O" : "");
+
+ i_size_write(inode, lov_merge_size(lsm, 0));
+ inode->i_blocks = lov_merge_blocks(lsm);
+ LTIME_S(inode->i_mtime) = lov_merge_mtime(lsm, LTIME_S(inode->i_mtime));
+ iattr->ia_size = inode->i_size;
+ LTIME_S(iattr->ia_mtime) = LTIME_S(inode->i_mtime);
+ iattr->ia_valid |= ATTR_SIZE | ATTR_MTIME;
+
+ DOWN_WRITE_I_ALLOC_SEM(inode);
+ mds_inode_unset_attrs_old(inode);
+ UP_WRITE_I_ALLOC_SEM(inode);
+
+ obd_cancel(obd->u.mds.mds_dt_exp, lsm, LCK_PR, &lockh);
+
+cleanup:
+ if (lsm != NULL)
+ obd_free_memmd(obd->u.mds.mds_dt_exp, &lsm);
+ if (lmm != NULL)
+ OBD_FREE(lmm, len);
+ RETURN(rc);
+}
+
+int mds_close(struct ptlrpc_request *req, int offset)