+#if CONFIG_NFS4
+ if ((nofp->nof_flags & NFS_OPEN_FILE_CREATE) && nofp->nof_creator && !force) {
+ if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) {
+ lck_mtx_unlock(&np->n_openlock);
+ if (busied) {
+ nfs_open_file_clear_busy(nofp);
+ }
+ if (inuse) {
+ nfs_mount_state_in_use_end(nmp, 0);
+ }
+ if (!nfs4_reopen(nofp, NULL)) {
+ goto restart;
+ }
+ }
+ nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE;
+ lck_mtx_unlock(&np->n_openlock);
+ error = nfs_close(np, nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE, ctx);
+ if (error) {
+ NP(np, "nfs_vnop_inactive: create close error: %d", error);
+ nofp->nof_flags |= NFS_OPEN_FILE_CREATE;
+ }
+ if (busied) {
+ nfs_open_file_clear_busy(nofp);
+ }
+ if (inuse) {
+ nfs_mount_state_in_use_end(nmp, error);
+ }
+ goto restart;
+ }
+#endif
+ if (nofp->nof_flags & NFS_OPEN_FILE_NEEDCLOSE) {
+ /*
+ * If the file is marked as needing reopen, but this was the only
+ * open on the file, just drop the open.
+ */
+ nofp->nof_flags &= ~NFS_OPEN_FILE_NEEDCLOSE;
+ if ((nofp->nof_flags & NFS_OPEN_FILE_REOPEN) && (nofp->nof_opencnt == 1)) {
+ nofp->nof_flags &= ~NFS_OPEN_FILE_REOPEN;
+ nofp->nof_r--;
+ nofp->nof_opencnt--;
+ nofp->nof_access = 0;
+ } else if (!force) {
+ lck_mtx_unlock(&np->n_openlock);
+ if (nofp->nof_flags & NFS_OPEN_FILE_REOPEN) {
+ if (busied) {
+ nfs_open_file_clear_busy(nofp);
+ }
+ if (inuse) {
+ nfs_mount_state_in_use_end(nmp, 0);
+ }
+#if CONFIG_NFS4
+ if (!nfs4_reopen(nofp, NULL)) {
+ goto restart;
+ }
+#endif
+ }
+ error = nfs_close(np, nofp, NFS_OPEN_SHARE_ACCESS_READ, NFS_OPEN_SHARE_DENY_NONE, ctx);
+ if (error) {
+ NP(np, "nfs_vnop_inactive: need close error: %d", error);
+ nofp->nof_flags |= NFS_OPEN_FILE_NEEDCLOSE;
+ }
+ if (busied) {
+ nfs_open_file_clear_busy(nofp);
+ }
+ if (inuse) {
+ nfs_mount_state_in_use_end(nmp, error);
+ }
+ goto restart;
+ }
+ }
+ if (nofp->nof_opencnt && !force) {
+ NP(np, "nfs_vnop_inactive: file still open: %d", nofp->nof_opencnt);
+ }
+ if (!force && (nofp->nof_access || nofp->nof_deny ||
+ nofp->nof_mmap_access || nofp->nof_mmap_deny ||
+ nofp->nof_r || nofp->nof_w || nofp->nof_rw ||
+ nofp->nof_r_dw || nofp->nof_w_dw || nofp->nof_rw_dw ||
+ nofp->nof_r_drw || nofp->nof_w_drw || nofp->nof_rw_drw ||
+ nofp->nof_d_r || nofp->nof_d_w || nofp->nof_d_rw ||
+ nofp->nof_d_r_dw || nofp->nof_d_w_dw || nofp->nof_d_rw_dw ||
+ nofp->nof_d_r_drw || nofp->nof_d_w_drw || nofp->nof_d_rw_drw)) {
+ NP(np, "nfs_vnop_inactive: non-zero access: %d %d %d %d # %u.%u %u.%u %u.%u dw %u.%u %u.%u %u.%u drw %u.%u %u.%u %u.%u",
+ nofp->nof_access, nofp->nof_deny,
+ nofp->nof_mmap_access, nofp->nof_mmap_deny,
+ nofp->nof_r, nofp->nof_d_r,
+ nofp->nof_w, nofp->nof_d_w,
+ nofp->nof_rw, nofp->nof_d_rw,
+ nofp->nof_r_dw, nofp->nof_d_r_dw,
+ nofp->nof_w_dw, nofp->nof_d_w_dw,
+ nofp->nof_rw_dw, nofp->nof_d_rw_dw,
+ nofp->nof_r_drw, nofp->nof_d_r_drw,
+ nofp->nof_w_drw, nofp->nof_d_w_drw,
+ nofp->nof_rw_drw, nofp->nof_d_rw_drw);
+ }
+ if (busied) {
+ nfs_open_file_clear_busy(nofp);
+ }
+ }
+ lck_mtx_unlock(&np->n_openlock);
+
+ if (inuse && nfs_mount_state_in_use_end(nmp, error)) {
+ goto restart;
+ }
+
+ nfs_node_lock_force(np);
+
+ if (vnode_vtype(vp) != VDIR) {
+ nsp = np->n_sillyrename;
+ np->n_sillyrename = NULL;
+ } else {
+ nsp = NULL;
+ }
+
+ FSDBG_TOP(264, vp, np, np->n_flag, nsp);
+
+ if (!nsp) {
+ /* no silly file to clean up... */
+ /* clear all flags other than these */
+ np->n_flag &= (NMODIFIED);
+ nfs_node_unlock(np);
+ FSDBG_BOT(264, vp, np, np->n_flag, 0);
+ return 0;
+ }
+ nfs_node_unlock(np);
+
+ /* Remove the silly file that was rename'd earlier */
+
+ /* flush all the buffers */
+ nfs_vinvalbuf2(vp, V_SAVE, vfs_context_thread(ctx), nsp->nsr_cred, 1);
+
+ /* try to get the latest attributes */
+ attrerr = nfs_getattr(np, &nvattr, ctx, NGA_UNCACHED);
+
+ /* Check if we should remove it from the node hash. */
+ /* Leave it if inuse or it has multiple hard links. */
+ if (vnode_isinuse(vp, 0) || (!attrerr && (nvattr.nva_nlink > 1))) {
+ unhash = 0;
+ } else {
+ unhash = 1;
+ ubc_setsize(vp, 0);
+ }
+
+ /* mark this node and the directory busy while we do the remove */
+ busyerror = nfs_node_set_busy2(nsp->nsr_dnp, np, vfs_context_thread(ctx));
+
+ /* lock the node while we remove the silly file */
+ lck_mtx_lock(nfs_node_hash_mutex);
+ while (np->n_hflag & NHLOCKED) {
+ np->n_hflag |= NHLOCKWANT;
+ msleep(np, nfs_node_hash_mutex, PINOD, "nfs_inactive", NULL);
+ }
+ np->n_hflag |= NHLOCKED;
+ lck_mtx_unlock(nfs_node_hash_mutex);
+
+ /* purge the name cache to deter others from finding it */
+ bzero(&cn, sizeof(cn));
+ cn.cn_nameptr = nsp->nsr_name;
+ cn.cn_namelen = nsp->nsr_namlen;
+ nfs_name_cache_purge(nsp->nsr_dnp, np, &cn, ctx);
+
+ FSDBG(264, np, np->n_size, np->n_vattr.nva_size, 0xf00d00f1);
+
+ /* now remove the silly file */
+ nfs_removeit(nsp);
+
+ /* clear all flags other than these */
+ nfs_node_lock_force(np);
+ np->n_flag &= (NMODIFIED);
+ nfs_node_unlock(np);
+
+ if (!busyerror) {
+ nfs_node_clear_busy2(nsp->nsr_dnp, np);
+ }
+
+ if (unhash && vnode_isinuse(vp, 0)) {
+ /* vnode now inuse after silly remove? */
+ unhash = 0;
+ ubc_setsize(vp, np->n_size);
+ }
+
+ lck_mtx_lock(nfs_node_hash_mutex);
+ if (unhash) {
+ /*
+ * remove nfsnode from hash now so we can't accidentally find it
+ * again if another object gets created with the same filehandle
+ * before this vnode gets reclaimed
+ */
+ if (np->n_hflag & NHHASHED) {
+ LIST_REMOVE(np, n_hash);
+ np->n_hflag &= ~NHHASHED;
+ FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
+ }
+ vnode_recycle(vp);
+ }
+ /* unlock the node */
+ np->n_hflag &= ~NHLOCKED;
+ if (np->n_hflag & NHLOCKWANT) {
+ np->n_hflag &= ~NHLOCKWANT;
+ wakeup(np);
+ }
+ lck_mtx_unlock(nfs_node_hash_mutex);
+
+ /* cleanup sillyrename info */
+ if (nsp->nsr_cred != NOCRED) {
+ kauth_cred_unref(&nsp->nsr_cred);
+ }
+ vnode_rele(NFSTOV(nsp->nsr_dnp));
+ FREE_ZONE(nsp, sizeof(*nsp), M_NFSREQ);
+
+ FSDBG_BOT(264, vp, np, np->n_flag, 0);
+ return 0;