oplock.c
来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 894 行 · 第 1/2 页
C
894 行
remove_oplock(fsp); return; } /* Ensure we're really at level2 state. */ SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK); /* Now send a break to none message to our client. */ break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); if (break_msg == NULL) { exit_server("Could not talloc break_msg\n"); } /* Need to wait before sending a break message if we sent ourselves this message. */ if (procid_to_pid(&src) == sys_getpid()) { wait_before_sending_break(); } /* Save the server smb signing state. */ sign_state = srv_oplock_set_signing(False); show_msg(break_msg); if (!send_smb(smbd_server_fd(), break_msg)) { exit_server("oplock_break: send_smb failed."); } /* Restore the sign state to what it was. */ srv_oplock_set_signing(sign_state); talloc_free(break_msg); /* Async level2 request, don't send a reply, just remove the oplock. */ remove_oplock(fsp);}/******************************************************************* This handles the generic oplock break message from another smbd.*******************************************************************/static void process_oplock_break_message(int msg_type, struct process_id src, void *buf, size_t len){ struct share_mode_entry msg; files_struct *fsp; char *break_msg; BOOL break_to_level2 = False; BOOL sign_state; if (buf == NULL) { DEBUG(0, ("Got NULL buffer\n")); return; } if (len != MSG_SMB_SHARE_MODE_ENTRY_SIZE) { DEBUG(0, ("Got invalid msg len %d\n", (int)len)); return; } /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, buf); DEBUG(10, ("Got oplock break message from pid %d: 0x%x/%.0f/%d\n", (int)procid_to_pid(&src), (unsigned int)msg.dev, (double)msg.inode, (int)msg.share_file_id)); fsp = initial_break_processing(msg.dev, msg.inode, msg.share_file_id); if (fsp == NULL) { /* a We hit race here. Break messages are sent, and before we * get to process this message, we have closed the file. Reply * with 'ok, oplock broken' */ DEBUG(3, ("Did not find fsp\n")); become_root(); /* We just send the same message back. */ message_send_pid(src, MSG_SMB_BREAK_RESPONSE, buf, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True); unbecome_root(); return; } if (fsp->sent_oplock_break != NO_BREAK_SENT) { /* Remember we have to inform the requesting PID when the * client replies */ msg.pid = src; ADD_TO_ARRAY(NULL, struct share_mode_entry, msg, &fsp->pending_break_messages, &fsp->num_pending_break_messages); return; } if (EXCLUSIVE_OPLOCK_TYPE(msg.op_type) && !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { DEBUG(3, ("Already downgraded oplock on 0x%x/%.0f: %s\n", (unsigned int)fsp->dev, (double)fsp->inode, fsp->fsp_name)); become_root(); /* We just send the same message back. */ message_send_pid(src, MSG_SMB_BREAK_RESPONSE, buf, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True); unbecome_root(); return; } if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && !koplocks && /* NOTE: we force levelII off for kernel oplocks - * this will change when it is supported */ lp_level2_oplocks(SNUM(fsp->conn))) { break_to_level2 = True; } break_msg = new_break_smb_message(NULL, fsp, break_to_level2 ? OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); if (break_msg == NULL) { exit_server("Could not talloc break_msg\n"); } /* Need to wait before sending a break message if we sent ourselves this message. */ if (procid_to_pid(&src) == sys_getpid()) { wait_before_sending_break(); } /* Save the server smb signing state. */ sign_state = srv_oplock_set_signing(False); show_msg(break_msg); if (!send_smb(smbd_server_fd(), break_msg)) { exit_server("oplock_break: send_smb failed."); } /* Restore the sign state to what it was. */ srv_oplock_set_signing(sign_state); talloc_free(break_msg); fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT; msg.pid = src; ADD_TO_ARRAY(NULL, struct share_mode_entry, msg, &fsp->pending_break_messages, &fsp->num_pending_break_messages); add_oplock_timeout_handler(fsp);}/******************************************************************* This handles the kernel oplock break message.*******************************************************************/static void process_kernel_oplock_break(int msg_type, struct process_id src, void *buf, size_t len){ SMB_DEV_T dev; SMB_INO_T inode; unsigned long file_id; files_struct *fsp; char *break_msg; BOOL sign_state; if (buf == NULL) { DEBUG(0, ("Got NULL buffer\n")); return; } if (len != MSG_SMB_KERNEL_BREAK_SIZE) { DEBUG(0, ("Got invalid msg len %d\n", (int)len)); return; } /* Pull the data from the message. */ dev = DEV_T_VAL(buf, 0); inode = INO_T_VAL(buf, 8); file_id = (unsigned long)IVAL(buf, 16); DEBUG(10, ("Got kernel oplock break message from pid %d: 0x%x/%.0f/%u\n", (int)procid_to_pid(&src), (unsigned int)dev, (double)inode, (unsigned int)file_id)); fsp = initial_break_processing(dev, inode, file_id); if (fsp == NULL) { DEBUG(3, ("Got a kernel oplock break message for a file " "I don't know about\n")); return; } if (fsp->sent_oplock_break != NO_BREAK_SENT) { /* This is ok, kernel oplocks come in completely async */ DEBUG(3, ("Got a kernel oplock request while waiting for a " "break reply\n")); return; } break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); if (break_msg == NULL) { exit_server("Could not talloc break_msg\n"); } /* Save the server smb signing state. */ sign_state = srv_oplock_set_signing(False); show_msg(break_msg); if (!send_smb(smbd_server_fd(), break_msg)) { exit_server("oplock_break: send_smb failed."); } /* Restore the sign state to what it was. */ srv_oplock_set_signing(sign_state); talloc_free(break_msg); fsp->sent_oplock_break = BREAK_TO_NONE_SENT; add_oplock_timeout_handler(fsp);}void reply_to_oplock_break_requests(files_struct *fsp){ int i; become_root(); for (i=0; i<fsp->num_pending_break_messages; i++) { struct share_mode_entry *e = &fsp->pending_break_messages[i]; char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; share_mode_entry_to_message(msg, e); message_send_pid(e->pid, MSG_SMB_BREAK_RESPONSE, msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True); } unbecome_root(); SAFE_FREE(fsp->pending_break_messages); fsp->num_pending_break_messages = 0; if (fsp->oplock_timeout != NULL) { /* Remove the timed event handler. */ talloc_free(fsp->oplock_timeout); fsp->oplock_timeout = NULL; } return;}static void process_oplock_break_response(int msg_type, struct process_id src, void *buf, size_t len){ struct share_mode_entry msg; if (buf == NULL) { DEBUG(0, ("Got NULL buffer\n")); return; } if (len != MSG_SMB_SHARE_MODE_ENTRY_SIZE) { DEBUG(0, ("Got invalid msg len %u\n", (unsigned int)len)); return; } /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, buf); DEBUG(10, ("Got oplock break response from pid %d: 0x%x/%.0f/%u mid %u\n", (int)procid_to_pid(&src), (unsigned int)msg.dev, (double)msg.inode, (unsigned int)msg.share_file_id, (unsigned int)msg.op_mid)); /* Here's the hack from open.c, store the mid in the 'port' field */ schedule_deferred_open_smb_message(msg.op_mid);}static void process_open_retry_message(int msg_type, struct process_id src, void *buf, size_t len){ struct share_mode_entry msg; if (buf == NULL) { DEBUG(0, ("Got NULL buffer\n")); return; } if (len != MSG_SMB_SHARE_MODE_ENTRY_SIZE) { DEBUG(0, ("Got invalid msg len %d\n", (int)len)); return; } /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, buf); DEBUG(10, ("Got open retry msg from pid %d: 0x%x/%.0f mid %u\n", (int)procid_to_pid(&src), (unsigned int)msg.dev, (double)msg.inode, (unsigned int)msg.op_mid)); schedule_deferred_open_smb_message(msg.op_mid);}/**************************************************************************** This function is called on any file modification or lock request. If a file is level 2 oplocked then it must tell all other level 2 holders to break to none.****************************************************************************/void release_level_2_oplocks_on_change(files_struct *fsp){ int i; struct share_mode_lock *lck; /* * If this file is level II oplocked then we need * to grab the shared memory lock and inform all * other files with a level II lock that they need * to flush their read caches. We keep the lock over * the shared memory area whilst doing this. */ if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) return; lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); if (lck == NULL) { DEBUG(0,("release_level_2_oplocks_on_change: failed to lock " "share mode entry for file %s.\n", fsp->fsp_name )); } DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n", lck->num_share_modes )); for(i = 0; i < lck->num_share_modes; i++) { struct share_mode_entry *share_entry = &lck->share_modes[i]; char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; if (!is_valid_share_mode_entry(share_entry)) { continue; } /* * As there could have been multiple writes waiting at the * lock_share_entry gate we may not be the first to * enter. Hence the state of the op_types in the share mode * entries may be partly NO_OPLOCK and partly LEVEL_II or FAKE_LEVEL_II * oplock. It will do no harm to re-send break messages to * those smbd's that are still waiting their turn to remove * their LEVEL_II state, and also no harm to ignore existing * NO_OPLOCK states. JRA. */ DEBUG(10,("release_level_2_oplocks_on_change: " "share_entry[%i]->op_type == %d\n", i, share_entry->op_type )); if (share_entry->op_type == NO_OPLOCK) { continue; } /* Paranoia .... */ if (EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) { DEBUG(0,("release_level_2_oplocks_on_change: PANIC. " "share mode entry %d is an exlusive " "oplock !\n", i )); talloc_free(lck); abort(); } share_mode_entry_to_message(msg, share_entry); become_root(); message_send_pid(share_entry->pid, MSG_SMB_ASYNC_LEVEL2_BREAK, msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True); unbecome_root(); } /* We let the message receivers handle removing the oplock state in the share mode lock db. */ talloc_free(lck);}/**************************************************************************** Linearize a share mode entry struct to an internal oplock break message.****************************************************************************/void share_mode_entry_to_message(char *msg, struct share_mode_entry *e){ SIVAL(msg,0,(uint32)e->pid.pid); SSVAL(msg,4,e->op_mid); SSVAL(msg,6,e->op_type); SIVAL(msg,8,e->access_mask); SIVAL(msg,12,e->share_access); SIVAL(msg,16,e->private_options); SIVAL(msg,20,(uint32)e->time.tv_sec); SIVAL(msg,24,(uint32)e->time.tv_usec); SDEV_T_VAL(msg,28,e->dev); SINO_T_VAL(msg,36,e->inode); SIVAL(msg,44,e->share_file_id);}/**************************************************************************** De-linearize an internal oplock break message to a share mode entry struct.****************************************************************************/void message_to_share_mode_entry(struct share_mode_entry *e, char *msg){ e->pid.pid = (pid_t)IVAL(msg,0); e->op_mid = SVAL(msg,4); e->op_type = SVAL(msg,6); e->access_mask = IVAL(msg,8); e->share_access = IVAL(msg,12); e->private_options = IVAL(msg,16); e->time.tv_sec = (time_t)IVAL(msg,20); e->time.tv_usec = (int)IVAL(msg,24); e->dev = DEV_T_VAL(msg,28); e->inode = INO_T_VAL(msg,36); e->share_file_id = (unsigned long)IVAL(msg,44);}/**************************************************************************** Setup oplocks for this process.****************************************************************************/BOOL init_oplocks(void){ DEBUG(3,("open_oplock_ipc: initializing messages.\n")); message_register(MSG_SMB_BREAK_REQUEST, process_oplock_break_message); message_register(MSG_SMB_ASYNC_LEVEL2_BREAK, process_oplock_async_level2_break_message); message_register(MSG_SMB_BREAK_RESPONSE, process_oplock_break_response); message_register(MSG_SMB_KERNEL_BREAK, process_kernel_oplock_break); message_register(MSG_SMB_OPEN_RETRY, process_open_retry_message); if (lp_kernel_oplocks()) {#if HAVE_KERNEL_OPLOCKS_IRIX koplocks = irix_init_kernel_oplocks();#elif HAVE_KERNEL_OPLOCKS_LINUX koplocks = linux_init_kernel_oplocks();#endif } return True;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?