From 165f5f3f40317c1e75d60a977270f903f7475f69 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 31 Dec 2006 10:16:03 +0000 Subject: r20433: Work in progress: Survive more of RAW-NOTIFY. 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 | 98 +++++++++++++++++++++++++++++++++------------- source3/smbd/notify_hash.c | 3 ++ source3/smbd/nttrans.c | 11 ++++++ source3/smbd/open.c | 36 ++++++++++------- source3/smbd/reply.c | 21 +++++++++- 5 files changed, 126 insertions(+), 43 deletions(-) (limited to 'source3') diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index 2a5d7fc552..674505ac5b 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -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; } diff --git a/source3/smbd/notify_hash.c b/source3/smbd/notify_hash.c index 0787a3eec5..5d211ada01 100644 --- a/source3/smbd/notify_hash.c +++ b/source3/smbd/notify_hash.c @@ -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. */ diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 976ecf4524..f51d01fb9c 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -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)); } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 040b0543aa..895dd48221 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -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); /* diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index f10b649bf1..935e8033a5 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -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; } -- cgit