r20433: Work in progress: Survive more of RAW-NOTIFY.
authorVolker Lendecke <vlendec@samba.org>
Sun, 31 Dec 2006 10:16:03 +0000 (10:16 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:16:49 +0000 (12:16 -0500)
call_nt_transact_notify_change() is now sync if there are changes around.

A notify_message does a direct reply from within the message, so
process_pending_change_notify_queue is not needed anymore for samba-generated
events. Next step is to restructure the kernel-mechanisms to generate
messages.

Volker
(This used to be commit c813f71d0036ec52c99a97e60fe33ee47d0635fa)

source3/smbd/notify.c
source3/smbd/notify_hash.c
source3/smbd/nttrans.c
source3/smbd/open.c
source3/smbd/reply.c

index 2a5d7fc5525796ff6605b46dd4a16af7faff66e8..674505ac5bc72869f3de35a87d26867ef20819ae 100644 (file)
@@ -33,7 +33,6 @@ static struct cnotify_fns *cnotify;
 struct change_notify {
        struct change_notify *next, *prev;
        files_struct *fsp;
-       connection_struct *conn;
        uint32 flags;
        uint32 max_param_count;
        char request_buf[smb_size];
@@ -97,13 +96,13 @@ static BOOL notify_marshall_changes(struct notify_changes *changes,
  Setup the common parts of the return packet and send it.
 *****************************************************************************/
 
-static void change_notify_reply_packet(struct change_notify *notify,
+static void change_notify_reply_packet(const char *request_buf,
                                       NTSTATUS error_code)
 {
        char outbuf[smb_size+38];
 
        memset(outbuf, '\0', sizeof(outbuf));
-       construct_reply_common(notify->request_buf, outbuf);
+       construct_reply_common(request_buf, outbuf);
 
        ERROR_NT(error_code);
 
@@ -118,34 +117,34 @@ static void change_notify_reply_packet(struct change_notify *notify,
                exit_server_cleanly("change_notify_reply_packet: send_smb failed.");
 }
 
-static void change_notify_reply(struct change_notify *notify)
+void change_notify_reply(const char *request_buf, uint32 max_param_count,
+                        files_struct *fsp)
 {
        char *outbuf = NULL;
        prs_struct ps;
-       size_t buflen = smb_size+38+notify->max_param_count;
+       size_t buflen = smb_size+38+max_param_count;
 
        if (!prs_init(&ps, 0, NULL, False)
-           || !notify_marshall_changes(notify->fsp->notify, &ps)) {
-               change_notify_reply_packet(notify, NT_STATUS_NO_MEMORY);
+           || !notify_marshall_changes(fsp->notify, &ps)) {
+               change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
                goto done;
        }
 
-       if (prs_offset(&ps) > notify->max_param_count) {
+       if (prs_offset(&ps) > max_param_count) {
                /*
                 * We exceed what the client is willing to accept. Send
                 * nothing.
                 */
-               change_notify_reply_packet(notify, NT_STATUS_OK);
+               change_notify_reply_packet(request_buf, NT_STATUS_OK);
                goto done;
        }
 
        if (!(outbuf = SMB_MALLOC_ARRAY(char, buflen))) {
-               change_notify_reply_packet(notify, NT_STATUS_NO_MEMORY);
+               change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
                goto done;
        }
 
-       memset(outbuf, '\0', sizeof(outbuf));
-       construct_reply_common(notify->request_buf, outbuf);
+       construct_reply_common(request_buf, outbuf);
 
        if (send_nt_replies(outbuf, buflen, NT_STATUS_OK, prs_data_p(&ps),
                            prs_offset(&ps), NULL, 0) == -1) {
@@ -155,8 +154,8 @@ static void change_notify_reply(struct change_notify *notify)
  done:
        SAFE_FREE(outbuf);
        prs_mem_free(&ps);
-       notify->fsp->notify->num_changes = 0;
-       TALLOC_FREE(notify->fsp->notify->changes);
+       fsp->notify->num_changes = 0;
+       TALLOC_FREE(fsp->notify->changes);
 }
 
 /****************************************************************************
@@ -183,7 +182,7 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp, NTSTATUS st
        for (cnbp=change_notify_list; cnbp; cnbp=next) {
                next=cnbp->next;
                if (cnbp->fsp->fnum == fsp->fnum) {
-                       change_notify_reply_packet(cnbp, status);
+                       change_notify_reply_packet(cnbp->request_buf, status);
                        change_notify_remove(cnbp);
                }
        }
@@ -200,7 +199,8 @@ void remove_pending_change_notify_requests_by_mid(int mid)
        for (cnbp=change_notify_list; cnbp; cnbp=next) {
                next=cnbp->next;
                if(SVAL(cnbp->request_buf,smb_mid) == mid) {
-                       change_notify_reply_packet(cnbp, NT_STATUS_CANCELLED);
+                       change_notify_reply_packet(cnbp->request_buf,
+                                                  NT_STATUS_CANCELLED);
                        change_notify_remove(cnbp);
                }
        }
@@ -222,7 +222,7 @@ void remove_pending_change_notify_requests_by_filename(files_struct *fsp, NTSTAT
                 * the filename are identical.
                 */
                if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
-                       change_notify_reply_packet(cnbp, status);
+                       change_notify_reply_packet(cnbp->request_buf, status);
                        change_notify_remove(cnbp);
                }
        }
@@ -265,13 +265,25 @@ BOOL process_pending_change_notify_queue(time_t t)
 
                vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid);
 
-               if ((cnbp->fsp->notify->num_changes != 0)
-                   || cnotify->check_notify(cnbp->conn, vuid,
-                                            cnbp->fsp->fsp_name, cnbp->flags,
-                                            cnbp->change_data, t)) {
+               if (cnbp->fsp->notify->num_changes != 0) {
+                       DEBUG(10,("process_pending_change_notify_queue: %s "
+                                 "has %d changes!\n", cnbp->fsp->fsp_name,
+                                 cnbp->fsp->notify->num_changes));
+                       change_notify_reply(cnbp->request_buf,
+                                           cnbp->max_param_count,
+                                           cnbp->fsp);
+                       change_notify_remove(cnbp);
+                       continue;
+               }
+
+               if (cnotify->check_notify(cnbp->fsp->conn, vuid,
+                                         cnbp->fsp->fsp_name, cnbp->flags,
+                                         cnbp->change_data, t)) {
                        DEBUG(10,("process_pending_change_notify_queue: dir "
                                  "%s changed !\n", cnbp->fsp->fsp_name ));
-                       change_notify_reply(cnbp);
+                       change_notify_reply(cnbp->request_buf,
+                                           cnbp->max_param_count,
+                                           cnbp->fsp);
                        change_notify_remove(cnbp);
                }
        }
@@ -300,7 +312,6 @@ BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn,
 
        memcpy(cnbp->request_buf, inbuf, smb_size);
        cnbp->fsp = fsp;
-       cnbp->conn = conn;
        cnbp->flags = flags;
        cnbp->max_param_count = max_param_count;
        cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name,
@@ -393,6 +404,9 @@ void notify_action(connection_struct *conn, const char *parent,
        struct process_id *pids;
        int num_pids;
 
+       DEBUG(10, ("notify_action: parent=%s, name=%s, action=%u\n",
+                  parent, name, (unsigned)action));
+
        if (SMB_VFS_STAT(conn, parent, &sbuf) != 0) {
                /*
                 * Not 100% critical, ignore failure
@@ -458,12 +472,13 @@ void notify_action(connection_struct *conn, const char *parent,
        TALLOC_FREE(lck);
 }
 
-static void notify_message(int msgtype, struct process_id pid,
-                          void *buf, size_t len)
+static void notify_message_callback(int msgtype, struct process_id pid,
+                                   void *buf, size_t len)
 {
        struct notify_message msg;
        files_struct *fsp;
        struct notify_change *changes, *change;
+       struct change_notify *cnbp;
 
        if (!buf_to_notify_message(buf, len, &msg)) {
                return;
@@ -472,7 +487,24 @@ static void notify_message(int msgtype, struct process_id pid,
        DEBUG(10, ("Received notify_message for 0x%x/%.0f: %d\n",
                   (unsigned)msg.dev, (double)msg.inode, msg.action));
 
-       if (!(fsp = file_find_dir_lowest_id(msg.dev, msg.inode))) {
+       fsp = NULL;
+
+       for (cnbp = change_notify_list; cnbp != NULL; cnbp = cnbp->next) {
+               if ((cnbp->fsp->dev == msg.dev)
+                   && (cnbp->fsp->inode == msg.inode)) {
+                       break;
+               }
+       }
+
+       if (cnbp != NULL) {
+               DEBUG(10, ("Found pending change notify for %s\n",
+                          cnbp->fsp->fsp_name));
+               fsp = cnbp->fsp;
+               SMB_ASSERT(fsp->notify->num_changes == 0);
+       }
+
+       if ((fsp == NULL)
+           && !(fsp = file_find_dir_lowest_id(msg.dev, msg.inode))) {
                DEBUG(10, ("notify_message: did not find fsp\n"));
                return;
        }
@@ -494,6 +526,18 @@ static void notify_message(int msgtype, struct process_id pid,
        }
        change->action = msg.action;
        fsp->notify->num_changes += 1;
+
+       if (cnbp != NULL) {
+               /*
+                * Respond directly, we have a someone waiting for this change
+                */
+               DEBUG(10, ("Found pending cn for %s, responding directly\n",
+                          cnbp->fsp->fsp_name));
+               change_notify_reply(cnbp->request_buf, cnbp->max_param_count,
+                                   cnbp->fsp);
+               change_notify_remove(cnbp);
+               return;
+       }
 }
 
 /****************************************************************************
@@ -519,7 +563,7 @@ BOOL init_change_notify(void)
                return False;
        }
 
-       message_register(MSG_SMB_NOTIFY, notify_message);
+       message_register(MSG_SMB_NOTIFY, notify_message_callback);
 
        return True;
 }
index 0787a3eec5e2a7e68acf0bcb4aa2f8077bbf5869..5d211ada01ac0714f497c466dcd8e47846a0b90c 100644 (file)
@@ -186,6 +186,9 @@ static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path,
        struct change_data data2;
        int cnto = lp_change_notify_timeout(SNUM(conn));
 
+       DEBUG(10, ("hash_change_notify called for path %s\n", path));
+       return False;
+
        if (t && cnto <= 0) {
                /* Change notify turned off on this share.
                 * Only scan when (t==0) - we think something changed. */
index 976ecf45241435d574a50ad34149dda7889d81ab..f51d01fb9c8e40abb7c7dea7ae893f85f98a54ff 100644 (file)
@@ -1847,6 +1847,17 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
                return ERROR_DOS(ERRDOS,ERRbadfid);
        }
 
+       if (fsp->notify->num_changes > 0) {
+
+               change_notify_reply(inbuf, max_param_count, fsp);
+
+               /*
+                * change_notify_reply() above has independently sent its
+                * results
+                */
+               return -1;
+       }
+
        if (!change_notify_set(inbuf, fsp, conn, flags, max_param_count)) {
                return(UNIXERROR(ERRDOS,ERRbadfid));
        }
index 040b0543aaff8909753e3ec107c570de17e2e38a..895dd482214b40341f99082246c70f22a4def93d 100644 (file)
@@ -198,7 +198,8 @@ static void change_dir_owner_to_parent(connection_struct *conn,
 static NTSTATUS open_file(files_struct *fsp,
                          connection_struct *conn,
                          const char *parent_dir,
-                         const char *fname,
+                         const char *name,
+                         const char *path,
                          SMB_STRUCT_STAT *psbuf,
                          int flags,
                          mode_t unx_mode,
@@ -227,7 +228,7 @@ static NTSTATUS open_file(files_struct *fsp,
        if (!CAN_WRITE(conn)) {
                /* It's a read-only share - fail if we wanted to write. */
                if(accmode != O_RDONLY) {
-                       DEBUG(3,("Permission denied opening %s\n",fname));
+                       DEBUG(3,("Permission denied opening %s\n", path));
                        return NT_STATUS_ACCESS_DENIED;
                } else if(flags & O_CREAT) {
                        /* We don't want to write - but we must make sure that
@@ -253,7 +254,7 @@ static NTSTATUS open_file(files_struct *fsp,
 
        if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {
                DEBUG(10,("open_file: truncate requested on read-only open "
-                         "for file %s\n",fname ));
+                         "for file %s\n", path));
                local_flags = (flags & ~O_ACCMODE)|O_RDWR;
        }
 
@@ -282,15 +283,15 @@ static NTSTATUS open_file(files_struct *fsp,
 
                /* Don't create files with Microsoft wildcard characters. */
                if ((local_flags & O_CREAT) && !file_existed &&
-                   ms_has_wild(fname))  {
+                   ms_has_wild(path))  {
                        return NT_STATUS_OBJECT_NAME_INVALID;
                }
 
                /* Actually do the open */
-               if (!fd_open(conn, fname, fsp, local_flags, unx_mode)) {
+               if (!fd_open(conn, path, fsp, local_flags, unx_mode)) {
                        DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
                                 "(flags=%d)\n",
-                                fname,strerror(errno),local_flags,flags));
+                                path,strerror(errno),local_flags,flags));
                        return map_nt_error_from_unix(errno);
                }
 
@@ -298,7 +299,7 @@ static NTSTATUS open_file(files_struct *fsp,
 
                        /* Inherit the ACL if required */
                        if (lp_inherit_perms(SNUM(conn))) {
-                               inherit_access_acl(conn, parent_dir, fname,
+                               inherit_access_acl(conn, parent_dir, path,
                                                   unx_mode);
                        }
 
@@ -307,6 +308,9 @@ static NTSTATUS open_file(files_struct *fsp,
                                change_file_owner_to_parent(conn, parent_dir,
                                                            fsp);
                        }
+
+                       notify_action(conn, parent_dir, name,
+                                     NOTIFY_ACTION_ADDED);
                }
 
        } else {
@@ -317,13 +321,13 @@ static NTSTATUS open_file(files_struct *fsp,
                int ret;
 
                if (fsp->fh->fd == -1) {
-                       ret = SMB_VFS_STAT(conn, fname, psbuf);
+                       ret = SMB_VFS_STAT(conn, path, psbuf);
                } else {
                        ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf);
                        /* If we have an fd, this stat should succeed. */
                        if (ret == -1) {
                                DEBUG(0,("Error doing fstat on open file %s "
-                                        "(%s)\n", fname,strerror(errno) ));
+                                        "(%s)\n", path,strerror(errno) ));
                        }
                }
 
@@ -365,12 +369,13 @@ static NTSTATUS open_file(files_struct *fsp,
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->is_directory = False;
        fsp->is_stat = False;
-       if (conn->aio_write_behind_list &&
-           is_in_path(fname, conn->aio_write_behind_list, conn->case_sensitive)) {
+       if (conn->aio_write_behind_list
+           && is_in_path(path, conn->aio_write_behind_list,
+                         conn->case_sensitive)) {
                fsp->aio_write_behind = True;
        }
 
-       string_set(&fsp->fsp_name,fname);
+       string_set(&fsp->fsp_name, path);
        fsp->wcp = NULL; /* Write cache pointer. */
 
        DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
@@ -1579,8 +1584,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
         * open_file strips any O_TRUNC flags itself.
         */
 
-       fsp_open = open_file(fsp, conn, parent_dir, fname, psbuf, flags|flags2,
-                            unx_mode, access_mask, open_access_mask);
+       fsp_open = open_file(fsp, conn, parent_dir, newname, fname, psbuf,
+                            flags|flags2, unx_mode, access_mask,
+                            open_access_mask);
 
        if (!NT_STATUS_IS_OK(fsp_open)) {
                if (lck != NULL) {
@@ -1845,7 +1851,7 @@ NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
 
        /* note! we must use a non-zero desired access or we don't get
            a real file descriptor. Oh what a twisted web we weave. */
-       status = open_file(fsp, conn, NULL, fname, psbuf, O_WRONLY, 0,
+       status = open_file(fsp, conn, NULL, NULL, fname, psbuf, O_WRONLY, 0,
                           FILE_WRITE_DATA, FILE_WRITE_DATA);
 
        /* 
index f10b649bf191891fac5dfa78ca55e114bef5aaaa..935e8033a57c79b5b14f290f9299eec6d02a7b58 100644 (file)
@@ -1975,10 +1975,12 @@ NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL b
  code.
 ****************************************************************************/
 
-NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, char *name, BOOL has_wild)
+NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
+                         char *name, BOOL has_wild)
 {
        pstring directory;
        pstring mask;
+       pstring orig_name;
        char *p;
        int count=0;
        NTSTATUS error = NT_STATUS_OK;
@@ -1989,6 +1991,11 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, char *name, B
        *directory = *mask = 0;
        
        rc = unix_convert(name,conn,0,&bad_path,&sbuf);
+
+       /*
+        * Feel my pain, this code needs rewriting *very* badly! -- vl
+        */
+       pstrcpy(orig_name, name);
        
        p = strrchr_m(name,'/');
        if (!p) {
@@ -2089,6 +2096,18 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, char *name, B
                error = map_nt_error_from_unix(errno);
        }
 
+       {
+               char *dir;
+               const char *fname;
+
+               if (parent_dirname_talloc(tmp_talloc_ctx(), orig_name,
+                                         &dir, &fname)) {
+                       notify_action(conn, dir, fname,
+                                     NOTIFY_ACTION_REMOVED);
+                       TALLOC_FREE(dir); /* not strictly necessary */
+               }
+       }
+
        return error;
 }