diff options
Diffstat (limited to 'fs/cifs/cifsglob.h')
-rw-r--r-- | fs/cifs/cifsglob.h | 135 |
1 files changed, 91 insertions, 44 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a643c84ff1e9..3070407cafa7 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -605,6 +605,7 @@ inc_rfc1001_len(void *buf, int count) struct TCP_Server_Info { struct list_head tcp_ses_list; struct list_head smb_ses_list; + spinlock_t srv_lock; /* protect anything here that is not protected */ __u64 conn_id; /* connection identifier (useful for debugging) */ int srv_count; /* reference counter */ /* 15 character server name + 0x20 16th byte indicating type = srv */ @@ -622,6 +623,7 @@ struct TCP_Server_Info { #endif wait_queue_head_t response_q; wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ + spinlock_t mid_lock; /* protect mid queue and it's entries */ struct list_head pending_mid_q; bool noblocksnd; /* use blocking sendmsg */ bool noautotune; /* do not autotune send buf sizes */ @@ -1008,6 +1010,7 @@ struct cifs_ses { struct list_head rlist; /* reconnect list */ struct list_head tcon_list; struct cifs_tcon *tcon_ipc; + spinlock_t ses_lock; /* protect anything here that is not protected */ struct mutex session_mutex; struct TCP_Server_Info *server; /* pointer to server info */ int ses_count; /* reference counter */ @@ -1169,6 +1172,7 @@ struct cifs_tcon { struct list_head tcon_list; int tc_count; struct list_head rlist; /* reconnect list */ + spinlock_t tc_lock; /* protect anything here that is not protected */ atomic_t num_local_opens; /* num of all opens including disconnected */ atomic_t num_remote_opens; /* num of all network opens on server */ struct list_head openFileList; @@ -1899,33 +1903,78 @@ require use of the stronger protocol */ */ /**************************************************************************** - * Locking notes. All updates to global variables and lists should be - * protected by spinlocks or semaphores. + * Here are all the locks (spinlock, mutex, semaphore) in cifs.ko, arranged according + * to the locking order. i.e. if two locks are to be held together, the lock that + * appears higher in this list needs to be taken before the other. * - * Spinlocks - * --------- - * GlobalMid_Lock protects: - * list operations on pending_mid_q and oplockQ - * updates to XID counters, multiplex id and SMB sequence numbers - * list operations on global DnotifyReqList - * updates to ses->status and TCP_Server_Info->tcpStatus - * updates to server->CurrentMid - * tcp_ses_lock protects: - * list operations on tcp and SMB session lists - * tcon->open_file_lock protects the list of open files hanging off the tcon - * inode->open_file_lock protects the openFileList hanging off the inode - * cfile->file_info_lock protects counters and fields in cifs file struct - * f_owner.lock protects certain per file struct operations - * mapping->page_lock protects certain per page operations + * If you hold a lock that is lower in this list, and you need to take a higher lock + * (or if you think that one of the functions that you're calling may need to), first + * drop the lock you hold, pick up the higher lock, then the lower one. This will + * ensure that locks are picked up only in one direction in the below table + * (top to bottom). * - * Note that the cifs_tcon.open_file_lock should be taken before - * not after the cifsInodeInfo.open_file_lock + * Also, if you expect a function to be called with a lock held, explicitly document + * this in the comments on top of your function definition. * - * Semaphores - * ---------- - * cifsInodeInfo->lock_sem protects: - * the list of locks held by the inode + * And also, try to keep the critical sections (lock hold time) to be as minimal as + * possible. Blocking / calling other functions with a lock held always increase + * the risk of a possible deadlock. * + * Following this rule will avoid unnecessary deadlocks, which can get really hard to + * debug. Also, any new lock that you introduce, please add to this list in the correct + * order. + * + * Please populate this list whenever you introduce new locks in your changes. Or in + * case I've missed some existing locks. Please ensure that it's added in the list + * based on the locking order expected. + * + * ===================================================================================== + * Lock Protects Initialization fn + * ===================================================================================== + * vol_list_lock + * vol_info->ctx_lock vol_info->ctx + * cifs_sb_info->tlink_tree_lock cifs_sb_info->tlink_tree cifs_setup_cifs_sb + * TCP_Server_Info-> TCP_Server_Info cifs_get_tcp_session + * reconnect_mutex + * TCP_Server_Info->srv_mutex TCP_Server_Info cifs_get_tcp_session + * cifs_ses->session_mutex cifs_ses sesInfoAlloc + * cifs_tcon + * cifs_tcon->open_file_lock cifs_tcon->openFileList tconInfoAlloc + * cifs_tcon->pending_opens + * cifs_tcon->stat_lock cifs_tcon->bytes_read tconInfoAlloc + * cifs_tcon->bytes_written + * cifs_tcp_ses_lock cifs_tcp_ses_list sesInfoAlloc + * GlobalMid_Lock GlobalMaxActiveXid init_cifs + * GlobalCurrentXid + * GlobalTotalActiveXid + * TCP_Server_Info->srv_lock (anything in struct not protected by another lock and can change) + * TCP_Server_Info->mid_lock TCP_Server_Info->pending_mid_q cifs_get_tcp_session + * ->CurrentMid + * (any changes in mid_q_entry fields) + * TCP_Server_Info->req_lock TCP_Server_Info->in_flight cifs_get_tcp_session + * ->credits + * ->echo_credits + * ->oplock_credits + * ->reconnect_instance + * cifs_ses->ses_lock (anything that is not protected by another lock and can change) + * cifs_ses->iface_lock cifs_ses->iface_list sesInfoAlloc + * ->iface_count + * ->iface_last_update + * cifs_ses->chan_lock cifs_ses->chans + * ->chans_need_reconnect + * ->chans_in_reconnect + * cifs_tcon->tc_lock (anything that is not protected by another lock and can change) + * cifsInodeInfo->open_file_lock cifsInodeInfo->openFileList cifs_alloc_inode + * cifsInodeInfo->writers_lock cifsInodeInfo->writers cifsInodeInfo_alloc + * cifsInodeInfo->lock_sem cifsInodeInfo->llist cifs_init_once + * ->can_cache_brlcks + * cifsInodeInfo->deferred_lock cifsInodeInfo->deferred_closes cifsInodeInfo_alloc + * cached_fid->fid_mutex cifs_tcon->crfid tconInfoAlloc + * cifsFileInfo->fh_mutex cifsFileInfo cifs_new_fileinfo + * cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo + * ->invalidHandle initiate_cifs_search + * ->oplock_break_cancelled + * cifs_aio_ctx->aio_mutex cifs_aio_ctx cifs_aio_ctx_alloc ****************************************************************************/ #ifdef DECLARE_GLOBALS_HERE @@ -1941,47 +1990,44 @@ require use of the stronger protocol */ * sessions (and from that the tree connections) can be found * by iterating over cifs_tcp_ses_list */ -GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; +extern struct list_head cifs_tcp_ses_list; /* * This lock protects the cifs_tcp_ses_list, the list of smb sessions per * tcp session, and the list of tcon's per smb session. It also protects - * the reference counters for the server, smb session, and tcon. It also - * protects some fields in the TCP_Server_Info struct such as dstaddr. Finally, - * changes to the tcon->tidStatus should be done while holding this lock. + * the reference counters for the server, smb session, and tcon. * generally the locks should be taken in order tcp_ses_lock before * tcon->open_file_lock and that before file->file_info_lock since the * structure order is cifs_socket-->cifs_ses-->cifs_tcon-->cifs_file */ -GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock; +extern spinlock_t cifs_tcp_ses_lock; /* * Global transaction id (XID) information */ -GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ -GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ -GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ -GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ - /* on midQ entries */ +extern unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ +extern unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ +extern unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ +extern spinlock_t GlobalMid_Lock; /* protects above & list operations on midQ entries */ + /* * Global counters, updated atomically */ -GLOBAL_EXTERN atomic_t sesInfoAllocCount; -GLOBAL_EXTERN atomic_t tconInfoAllocCount; -GLOBAL_EXTERN atomic_t tcpSesNextId; -GLOBAL_EXTERN atomic_t tcpSesAllocCount; -GLOBAL_EXTERN atomic_t tcpSesReconnectCount; -GLOBAL_EXTERN atomic_t tconInfoReconnectCount; +extern atomic_t sesInfoAllocCount; +extern atomic_t tconInfoAllocCount; +extern atomic_t tcpSesNextId; +extern atomic_t tcpSesAllocCount; +extern atomic_t tcpSesReconnectCount; +extern atomic_t tconInfoReconnectCount; /* Various Debug counters */ -GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */ +extern atomic_t buf_alloc_count; /* current number allocated */ +extern atomic_t small_buf_alloc_count; #ifdef CONFIG_CIFS_STATS2 -GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */ -GLOBAL_EXTERN atomic_t totSmBufAllocCount; +extern atomic_t total_buf_alloc_count; /* total allocated over all time */ +extern atomic_t total_small_buf_alloc_count; extern unsigned int slow_rsp_threshold; /* number of secs before logging */ #endif -GLOBAL_EXTERN atomic_t smBufAllocCount; -GLOBAL_EXTERN atomic_t midCount; /* Misc globals */ extern bool enable_oplocks; /* enable or disable oplocks */ @@ -1998,6 +2044,7 @@ extern unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ extern unsigned int cifs_min_small; /* min size of small buf pool */ extern unsigned int cifs_max_pending; /* MAX requests at once to server*/ extern bool disable_legacy_dialects; /* forbid vers=1.0 and vers=2.0 mounts */ +extern atomic_t mid_count; void cifs_oplock_break(struct work_struct *work); void cifs_queue_oplock_break(struct cifsFileInfo *cfile); |