Print this page
We've seen a situation where the NFS4-client tries endlessly to return a
delegation. This happened after a server reboot. The server responds with
STALE_STATEID to the DELEGRETURN. This case is not directly handled by
nfs4_do_delegreturn. Instead, it triggers a recovery of the clientid, which
in turn triggers a reclaim of all open files for this server.
To find the open files, rtable4 is enumerated for each mount to the server.
This is supposed to reopen the file, so that the next DELEGRETURN will
succeed.
In this case, the rnode is not in the rtable-hash, so it never gets
recovered. This leads to an endless delegreturn-loop, iterated once per
second.
This fix tests on NFS4_STALE_STATEID in combination with the rnode not
being in the hash. In this case, it treats the error as fatal and just
discards the delegation.


1490                         nfs4_error_init(&e, EINTR);
1491                         nfs4delegreturn_save_lost_rqst(e.error, &lost_rqst,
1492                             cr, vp);
1493                         (void) nfs4_start_recovery(&e, mi, vp,
1494                             NULL, &rp->r_deleg_stateid,
1495                             lost_rqst.lr_op == OP_DELEGRETURN ?
1496                             &lost_rqst : NULL, OP_DELEGRETURN, NULL,
1497                             NULL, NULL);
1498                         nfs4_end_op(mi, vp, NULL, &recov_state, needrecov);
1499                         break;
1500                 }
1501 
1502                 nfs4delegreturn_otw(rp, cr, &e);
1503 
1504                 /*
1505                  * Ignore some errors on delegreturn; no point in marking
1506                  * the file dead on a state destroying operation.
1507                  */
1508                 if (e.error == 0 && (nfs4_recov_marks_dead(e.stat) ||
1509                     e.stat == NFS4ERR_BADHANDLE ||
1510                     e.stat == NFS4ERR_STALE))


1511                         needrecov = FALSE;
1512                 else
1513                         needrecov = nfs4_needs_recovery(&e, TRUE, vp->v_vfsp);
1514 
1515                 if (needrecov) {
1516                         nfs4delegreturn_save_lost_rqst(e.error, &lost_rqst,
1517                             cr, vp);
1518                         (void) nfs4_start_recovery(&e, mi, vp,
1519                             NULL, &rp->r_deleg_stateid,
1520                             lost_rqst.lr_op == OP_DELEGRETURN ?
1521                             &lost_rqst : NULL, OP_DELEGRETURN, NULL,
1522                             NULL, NULL);
1523                 } else {
1524                         nfs4delegreturn_cleanup_impl(rp, NULL, ncg);
1525                         done = TRUE;
1526                 }
1527 
1528                 nfs4_end_op(mi, vp, NULL, &recov_state, needrecov);
1529         }
1530         return (e.error);




1490                         nfs4_error_init(&e, EINTR);
1491                         nfs4delegreturn_save_lost_rqst(e.error, &lost_rqst,
1492                             cr, vp);
1493                         (void) nfs4_start_recovery(&e, mi, vp,
1494                             NULL, &rp->r_deleg_stateid,
1495                             lost_rqst.lr_op == OP_DELEGRETURN ?
1496                             &lost_rqst : NULL, OP_DELEGRETURN, NULL,
1497                             NULL, NULL);
1498                         nfs4_end_op(mi, vp, NULL, &recov_state, needrecov);
1499                         break;
1500                 }
1501 
1502                 nfs4delegreturn_otw(rp, cr, &e);
1503 
1504                 /*
1505                  * Ignore some errors on delegreturn; no point in marking
1506                  * the file dead on a state destroying operation.
1507                  */
1508                 if (e.error == 0 && (nfs4_recov_marks_dead(e.stat) ||
1509                     e.stat == NFS4ERR_BADHANDLE ||
1510                     e.stat == NFS4ERR_STALE ||
1511                     (e.stat == NFS4ERR_STALE_STATEID &&
1512                      !(rp->r_flags & R4HASHED))))
1513                         needrecov = FALSE;
1514                 else
1515                         needrecov = nfs4_needs_recovery(&e, TRUE, vp->v_vfsp);
1516 
1517                 if (needrecov) {
1518                         nfs4delegreturn_save_lost_rqst(e.error, &lost_rqst,
1519                             cr, vp);
1520                         (void) nfs4_start_recovery(&e, mi, vp,
1521                             NULL, &rp->r_deleg_stateid,
1522                             lost_rqst.lr_op == OP_DELEGRETURN ?
1523                             &lost_rqst : NULL, OP_DELEGRETURN, NULL,
1524                             NULL, NULL);
1525                 } else {
1526                         nfs4delegreturn_cleanup_impl(rp, NULL, ncg);
1527                         done = TRUE;
1528                 }
1529 
1530                 nfs4_end_op(mi, vp, NULL, &recov_state, needrecov);
1531         }
1532         return (e.error);