smbd:close: only remove kernel share modes if they had been taken at open
[sfrench/samba-autobuild/.git] / source3 / smbd / close.c
index 720ffa7b649d5089b18c6784a1e50f2faa2874cd..9d1f1a98afefd17ed02daeb28be297fae702ebf8 100644 (file)
@@ -24,6 +24,7 @@
 #include "printing.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
+#include "smbd/scavenger.h"
 #include "fake_file.h"
 #include "transfer_file.h"
 #include "auth.h"
@@ -46,7 +47,7 @@ static NTSTATUS check_magic(struct files_struct *fsp)
        char *fname = NULL;
        NTSTATUS status;
 
-       if (!*lp_magicscript(talloc_tos(), SNUM(conn))) {
+       if (!*lp_magic_script(talloc_tos(), SNUM(conn))) {
                return NT_STATUS_OK;
        }
 
@@ -62,13 +63,13 @@ static NTSTATUS check_magic(struct files_struct *fsp)
                p++;
        }
 
-       if (!strequal(lp_magicscript(talloc_tos(), SNUM(conn)),p)) {
+       if (!strequal(lp_magic_script(talloc_tos(), SNUM(conn)),p)) {
                status = NT_STATUS_OK;
                goto out;
        }
 
-       if (*lp_magicoutput(talloc_tos(), SNUM(conn))) {
-               magic_output = lp_magicoutput(talloc_tos(), SNUM(conn));
+       if (*lp_magic_output(talloc_tos(), SNUM(conn))) {
+               magic_output = lp_magic_output(talloc_tos(), SNUM(conn));
        } else {
                magic_output = talloc_asprintf(ctx,
                                "%s.out",
@@ -147,7 +148,7 @@ static NTSTATUS close_filestruct(files_struct *fsp)
        NTSTATUS status = NT_STATUS_OK;
 
        if (fsp->fh->fd != -1) {
-               if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) {
+               if(flush_write_cache(fsp, SAMBA_CLOSE_FLUSH) == -1) {
                        status = map_nt_error_from_unix(errno);
                }
                delete_write_cache(fsp);
@@ -156,109 +157,12 @@ static NTSTATUS close_filestruct(files_struct *fsp)
        return status;
 }
 
-static int compare_share_mode_times(const void *p1, const void *p2)
-{
-       const struct share_mode_entry *s1 = (const struct share_mode_entry *)p1;
-       const struct share_mode_entry *s2 = (const struct share_mode_entry *)p2;
-       return timeval_compare(&s1->time, &s2->time);
-}
-
-/****************************************************************************
- If any deferred opens are waiting on this close, notify them.
-****************************************************************************/
-
-static void notify_deferred_opens(struct smbd_server_connection *sconn,
-                                 struct share_mode_lock *lck)
-{
-       struct server_id self = messaging_server_id(sconn->msg_ctx);
-       uint32_t i, num_deferred;
-       struct share_mode_entry *deferred;
-
-       if (!should_notify_deferred_opens(sconn)) {
-               return;
-       }
-
-       num_deferred = 0;
-       for (i=0; i<lck->data->num_share_modes; i++) {
-               struct share_mode_entry *e = &lck->data->share_modes[i];
-
-               if (!is_deferred_open_entry(e)) {
-                       continue;
-               }
-               if (share_mode_stale_pid(lck->data, i)) {
-                       continue;
-               }
-               num_deferred += 1;
-       }
-       if (num_deferred == 0) {
-               return;
-       }
-
-       deferred = talloc_array(talloc_tos(), struct share_mode_entry,
-                               num_deferred);
-       if (deferred == NULL) {
-               return;
-       }
-
-       num_deferred = 0;
-       for (i=0; i<lck->data->num_share_modes; i++) {
-               struct share_mode_entry *e = &lck->data->share_modes[i];
-               if (is_deferred_open_entry(e)) {
-                       deferred[num_deferred] = *e;
-                       num_deferred += 1;
-               }
-       }
-
-       /*
-        * We need to sort the notifications by initial request time. Imagine
-        * two opens come in asyncronously, both conflicting with the open we
-        * just close here. If we don't sort the notifications, the one that
-        * came in last might get the response before the one that came in
-        * first. This is demonstrated with the smbtorture4 raw.mux test.
-        *
-        * As long as we had the UNUSED_SHARE_MODE_ENTRY, we happened to
-        * survive this particular test. Without UNUSED_SHARE_MODE_ENTRY, we
-        * shuffle the share mode entries around a bit, so that we do not
-        * survive raw.mux anymore.
-        *
-        * We could have kept the ordering in del_share_mode, but as the
-        * ordering was never formalized I think it is better to do it here
-        * where it is necessary.
-        */
-
-       qsort(deferred, num_deferred, sizeof(struct share_mode_entry),
-             compare_share_mode_times);
-
-       for (i=0; i<num_deferred; i++) {
-               struct share_mode_entry *e = &deferred[i];
-
-               if (serverid_equal(&self, &e->pid)) {
-                       /*
-                        * We need to notify ourself to retry the open.  Do
-                        * this by finding the queued SMB record, moving it to
-                        * the head of the queue and changing the wait time to
-                        * zero.
-                        */
-                       schedule_deferred_open_message_smb(sconn, e->op_mid);
-               } else {
-                       char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
-
-                       share_mode_entry_to_message(msg, e);
-
-                       messaging_send_buf(sconn->msg_ctx, e->pid,
-                                          MSG_SMB_OPEN_RETRY,
-                                          (uint8 *)msg,
-                                          MSG_SMB_SHARE_MODE_ENTRY_SIZE);
-               }
-       }
-       TALLOC_FREE(deferred);
-}
-
 /****************************************************************************
  Delete all streams
 ****************************************************************************/
 
-NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
+NTSTATUS delete_all_streams(connection_struct *conn,
+                       const struct smb_filename *smb_fname)
 {
        struct stream_struct *stream_info = NULL;
        int i;
@@ -266,7 +170,7 @@ NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
        TALLOC_CTX *frame = talloc_stackframe();
        NTSTATUS status;
 
-       status = vfs_streaminfo(conn, NULL, fname, talloc_tos(),
+       status = vfs_streaminfo(conn, NULL, smb_fname, talloc_tos(),
                                &num_streams, &stream_info);
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
@@ -291,18 +195,21 @@ NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
 
        for (i=0; i<num_streams; i++) {
                int res;
-               struct smb_filename *smb_fname_stream = NULL;
+               struct smb_filename *smb_fname_stream;
 
                if (strequal(stream_info[i].name, "::$DATA")) {
                        continue;
                }
 
-               status = create_synthetic_smb_fname(talloc_tos(), fname,
-                                                   stream_info[i].name, NULL,
-                                                   &smb_fname_stream);
+               smb_fname_stream = synthetic_smb_fname(talloc_tos(),
+                                       smb_fname->base_name,
+                                       stream_info[i].name,
+                                       NULL,
+                                       smb_fname->flags);
 
-               if (!NT_STATUS_IS_OK(status)) {
+               if (smb_fname_stream == NULL) {
                        DEBUG(0, ("talloc_aprintf failed\n"));
+                       status = NT_STATUS_NO_MEMORY;
                        goto fail;
                }
 
@@ -399,7 +306,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                        became_user = True;
                }
                fsp->delete_on_close = true;
-               set_delete_on_close_lck(fsp, lck, True,
+               set_delete_on_close_lck(fsp, lck,
                                get_current_nttok(conn),
                                get_current_utok(conn));
                if (became_user) {
@@ -423,7 +330,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                        if (e->name_hash != fsp->name_hash) {
                                continue;
                        }
-                       if (fsp->posix_open
+                       if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN)
                            && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
                                continue;
                        }
@@ -439,10 +346,6 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                }
        }
 
-       /* Notify any deferred opens waiting on this close. */
-       notify_deferred_opens(conn->sconn, lck);
-       reply_to_oplock_break_requests(fsp);
-
        /*
         * NT can set delete_on_close of the last open
         * reference to a file.
@@ -451,15 +354,8 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
        normal_close = (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE);
 
        if (!normal_close || !delete_file) {
-
-               if (!del_share_mode(lck, fsp)) {
-                       DEBUG(0, ("close_remove_share_mode: Could not delete "
-                                 "share entry for file %s\n",
-                                 fsp_str_dbg(fsp)));
-               }
-
-               TALLOC_FREE(lck);
-               return NT_STATUS_OK;
+               status = NT_STATUS_OK;
+               goto done;
        }
 
        /*
@@ -534,7 +430,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
        if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
            && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {
 
-               status = delete_all_streams(conn, fsp->fsp_name->base_name);
+               status = delete_all_streams(conn, fsp->fsp_name);
 
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(5, ("delete_all_streams failed: %s\n",
@@ -568,7 +464,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
         */
 
        fsp->delete_on_close = false;
-       set_delete_on_close_lck(fsp, lck, false, NULL, NULL);
+       reset_delete_on_close_lck(fsp, lck);
 
  done:
 
@@ -577,6 +473,18 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                pop_sec_ctx();
        }
 
+       if (fsp->kernel_share_modes_taken) {
+               int ret_flock;
+
+               /* remove filesystem sharemodes */
+               ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, 0, 0);
+               if (ret_flock == -1) {
+                       DEBUG(2, ("close_remove_share_mode: removing kernel "
+                                 "flock for %s failed: %s\n",
+                                 fsp_str_dbg(fsp), strerror(errno)));
+               }
+       }
+
        if (!del_share_mode(lck, fsp)) {
                DEBUG(0, ("close_remove_share_mode: Could not delete share "
                          "entry for file %s\n", fsp_str_dbg(fsp)));
@@ -706,8 +614,47 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
        NTSTATUS status = NT_STATUS_OK;
        NTSTATUS tmp;
        connection_struct *conn = fsp->conn;
+       bool is_durable = false;
+
+       if (fsp->num_aio_requests != 0) {
+
+               if (close_type != SHUTDOWN_CLOSE) {
+                       /*
+                        * reply_close and the smb2 close must have
+                        * taken care of this. No other callers of
+                        * close_file should ever have created async
+                        * I/O.
+                        *
+                        * We need to panic here because if we close()
+                        * the fd while we have outstanding async I/O
+                        * requests, in the worst case we could end up
+                        * writing to the wrong file.
+                        */
+                       DEBUG(0, ("fsp->num_aio_requests=%u\n",
+                                 fsp->num_aio_requests));
+                       smb_panic("can not close with outstanding aio "
+                                 "requests");
+               }
 
-       aio_fsp_close(fsp);
+               /*
+                * For shutdown close, just drop the async requests
+                * including a potential close request pending for
+                * this fsp. Drop the close request first, the
+                * destructor for the aio_requests would execute it.
+                */
+               TALLOC_FREE(fsp->deferred_close);
+
+               while (fsp->num_aio_requests != 0) {
+                       /*
+                        * The destructor of the req will remove
+                        * itself from the fsp.
+                        * Don't use TALLOC_FREE here, this will overwrite
+                        * what the destructor just wrote into
+                        * aio_requests[0].
+                        */
+                       talloc_free(fsp->aio_requests[0]);
+               }
+       }
 
        /*
         * If we're flushing on a close we can get a write
@@ -717,6 +664,75 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
        tmp = close_filestruct(fsp);
        status = ntstatus_keeperror(status, tmp);
 
+       if (NT_STATUS_IS_OK(status) && fsp->op != NULL) {
+               is_durable = fsp->op->global->durable;
+       }
+
+       if (close_type != SHUTDOWN_CLOSE) {
+               is_durable = false;
+       }
+
+       if (is_durable) {
+               DATA_BLOB new_cookie = data_blob_null;
+
+               tmp = SMB_VFS_DURABLE_DISCONNECT(fsp,
+                                       fsp->op->global->backend_cookie,
+                                       fsp->op,
+                                       &new_cookie);
+               if (NT_STATUS_IS_OK(tmp)) {
+                       struct timeval tv;
+                       NTTIME now;
+
+                       if (req != NULL) {
+                               tv = req->request_time;
+                       } else {
+                               tv = timeval_current();
+                       }
+                       now = timeval_to_nttime(&tv);
+
+                       data_blob_free(&fsp->op->global->backend_cookie);
+                       fsp->op->global->backend_cookie = new_cookie;
+
+                       fsp->op->compat = NULL;
+                       tmp = smbXsrv_open_close(fsp->op, now);
+                       if (!NT_STATUS_IS_OK(tmp)) {
+                               DEBUG(1, ("Failed to update smbXsrv_open "
+                                         "record when disconnecting durable "
+                                         "handle for file %s: %s - "
+                                         "proceeding with normal close\n",
+                                         fsp_str_dbg(fsp), nt_errstr(tmp)));
+                       }
+                       scavenger_schedule_disconnected(fsp);
+               } else {
+                       DEBUG(1, ("Failed to disconnect durable handle for "
+                                 "file %s: %s - proceeding with normal "
+                                 "close\n", fsp_str_dbg(fsp), nt_errstr(tmp)));
+               }
+               if (!NT_STATUS_IS_OK(tmp)) {
+                       is_durable = false;
+               }
+       }
+
+       if (is_durable) {
+               /*
+                * This is the case where we successfully disconnected
+                * a durable handle and closed the underlying file.
+                * In all other cases, we proceed with a genuine close.
+                */
+               DEBUG(10, ("%s disconnected durable handle for file %s\n",
+                          conn->session_info->unix_info->unix_name,
+                          fsp_str_dbg(fsp)));
+               file_free(req, fsp);
+               return NT_STATUS_OK;
+       }
+
+       if (fsp->op != NULL) {
+               /*
+                * Make sure the handle is not marked as durable anymore
+                */
+               fsp->op->global->durable = false;
+       }
+
        if (fsp->print_file) {
                /* FIXME: return spool errors */
                print_spool_end(fsp, close_type);
@@ -726,7 +742,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
 
        /* Remove the oplock before potentially deleting the file. */
        if(fsp->oplock_type) {
-               release_file_oplock(fsp);
+               remove_oplock(fsp);
        }
 
        /* If this is an old DOS or FCB open and we have multiple opens on
@@ -774,13 +790,13 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
        return status;
 }
 /****************************************************************************
Static function used by reply_rmdir to delete an entire directory
Function used by reply_rmdir to delete an entire directory
  tree recursively. Return True on ok, False on fail.
 ****************************************************************************/
 
-static bool recursive_rmdir(TALLOC_CTX *ctx,
-                       connection_struct *conn,
-                       struct smb_filename *smb_dname)
+bool recursive_rmdir(TALLOC_CTX *ctx,
+                    connection_struct *conn,
+                    struct smb_filename *smb_dname)
 {
        const char *dname = NULL;
        char *talloced = NULL;
@@ -791,7 +807,7 @@ static bool recursive_rmdir(TALLOC_CTX *ctx,
 
        SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
 
-       dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0);
+       dir_hnd = OpenDir(talloc_tos(), conn, smb_dname, NULL, 0);
        if(dir_hnd == NULL)
                return False;
 
@@ -799,7 +815,6 @@ static bool recursive_rmdir(TALLOC_CTX *ctx,
                struct smb_filename *smb_dname_full = NULL;
                char *fullname = NULL;
                bool do_break = true;
-               NTSTATUS status;
 
                if (ISDOT(dname) || ISDOTDOT(dname)) {
                        TALLOC_FREE(talloced);
@@ -822,10 +837,13 @@ static bool recursive_rmdir(TALLOC_CTX *ctx,
                        goto err_break;
                }
 
-               status = create_synthetic_smb_fname(talloc_tos(), fullname,
-                                                   NULL, NULL,
-                                                   &smb_dname_full);
-               if (!NT_STATUS_IS_OK(status)) {
+               smb_dname_full = synthetic_smb_fname(talloc_tos(),
+                                               fullname,
+                                               NULL,
+                                               NULL,
+                                               smb_dname->flags);
+               if (smb_dname_full == NULL) {
+                       errno = ENOMEM;
                        goto err_break;
                }
 
@@ -837,8 +855,7 @@ static bool recursive_rmdir(TALLOC_CTX *ctx,
                        if(!recursive_rmdir(ctx, conn, smb_dname_full)) {
                                goto err_break;
                        }
-                       if(SMB_VFS_RMDIR(conn,
-                                        smb_dname_full->base_name) != 0) {
+                       if(SMB_VFS_RMDIR(conn, smb_dname_full) != 0) {
                                goto err_break;
                        }
                } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
@@ -888,7 +905,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
                }
                ret = SMB_VFS_UNLINK(conn, smb_dname);
        } else {
-               ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
+               ret = SMB_VFS_RMDIR(conn, smb_dname);
        }
        if (ret == 0) {
                notify_fname(conn, NOTIFY_ACTION_REMOVED,
@@ -909,7 +926,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
                char *talloced = NULL;
                long dirpos = 0;
                struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
-                                                 smb_dname->base_name, NULL,
+                                                 smb_dname, NULL,
                                                  0);
 
                if(dir_hnd == NULL) {
@@ -940,7 +957,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
                /* We only have veto files/directories.
                 * Are we allowed to delete them ? */
 
-               if(!lp_recursive_veto_delete(SNUM(conn))) {
+               if(!lp_delete_veto_files(SNUM(conn))) {
                        TALLOC_FREE(dir_hnd);
                        errno = ENOTEMPTY;
                        goto err;
@@ -953,7 +970,6 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
                        struct smb_filename *smb_dname_full = NULL;
                        char *fullname = NULL;
                        bool do_break = true;
-                       NTSTATUS status;
 
                        if (ISDOT(dname) || ISDOTDOT(dname)) {
                                TALLOC_FREE(talloced);
@@ -975,12 +991,13 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
                                goto err_break;
                        }
 
-                       status = create_synthetic_smb_fname(talloc_tos(),
-                                                           fullname, NULL,
-                                                           NULL,
-                                                           &smb_dname_full);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               errno = map_errno_from_nt_status(status);
+                       smb_dname_full = synthetic_smb_fname(talloc_tos(),
+                                                       fullname,
+                                                       NULL,
+                                                       NULL,
+                                                       smb_dname->flags);
+                       if (smb_dname_full == NULL) {
+                               errno = ENOMEM;
                                goto err_break;
                        }
 
@@ -993,7 +1010,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
                                        goto err_break;
                                }
                                if(SMB_VFS_RMDIR(conn,
-                                       smb_dname_full->base_name) != 0) {
+                                       smb_dname_full) != 0) {
                                        goto err_break;
                                }
                        } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
@@ -1012,7 +1029,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
                }
                TALLOC_FREE(dir_hnd);
                /* Retry the rmdir */
-               ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
+               ret = SMB_VFS_RMDIR(conn, smb_dname);
        }
 
   err:
@@ -1045,6 +1062,13 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
        NTSTATUS status1 = NT_STATUS_OK;
        const struct security_token *del_nt_token = NULL;
        const struct security_unix_token *del_token = NULL;
+       NTSTATUS notify_status;
+
+       if (fsp->conn->sconn->using_smb2) {
+               notify_status = STATUS_NOTIFY_CLEANUP;
+       } else {
+               notify_status = NT_STATUS_OK;
+       }
 
        /*
         * NT can set delete_on_close of the last open
@@ -1071,7 +1095,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                }
                send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
                                               fsp->fsp_name->base_name);
-               set_delete_on_close_lck(fsp, lck, true,
+               set_delete_on_close_lck(fsp, lck,
                                get_current_nttok(fsp->conn),
                                get_current_utok(fsp->conn));
                fsp->delete_on_close = true;
@@ -1091,7 +1115,9 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                        struct share_mode_entry *e = &lck->data->share_modes[i];
                        if (is_valid_share_mode_entry(e) &&
                                        e->name_hash == fsp->name_hash) {
-                               if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
+                               if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
+                                   (e->flags & SHARE_MODE_FLAG_POSIX_OPEN))
+                               {
                                        continue;
                                }
                                if (serverid_equal(&self, &e->pid) &&
@@ -1132,7 +1158,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                if ((fsp->conn->fs_capabilities & FILE_NAMED_STREAMS)
                    && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {
 
-                       status = delete_all_streams(fsp->conn, fsp->fsp_name->base_name);
+                       status = delete_all_streams(fsp->conn, fsp->fsp_name);
                        if (!NT_STATUS_IS_OK(status)) {
                                DEBUG(5, ("delete_all_streams failed: %s\n",
                                          nt_errstr(status)));
@@ -1154,8 +1180,8 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                 * now fail as the directory has been deleted.
                 */
 
-               if(NT_STATUS_IS_OK(status)) {
-                       remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
+               if (NT_STATUS_IS_OK(status)) {
+                       notify_status = NT_STATUS_DELETE_PENDING;
                }
        } else {
                if (!del_share_mode(lck, fsp)) {
@@ -1164,10 +1190,10 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                }
 
                TALLOC_FREE(lck);
-               remove_pending_change_notify_requests_by_fid(
-                       fsp, NT_STATUS_OK);
        }
 
+       remove_pending_change_notify_requests_by_fid(fsp, notify_status);
+
        status1 = fd_close(fsp);
 
        if (!NT_STATUS_IS_OK(status1)) {