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 + -
显示快捷键?