From patchwork Sat Mar 12 03:24:05 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 629731 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p2C3O8B0022255 for ; Sat, 12 Mar 2011 03:24:08 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753151Ab1CLDYI (ORCPT ); Fri, 11 Mar 2011 22:24:08 -0500 Received: from mail-iw0-f174.google.com ([209.85.214.174]:62549 "EHLO mail-iw0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753967Ab1CLDYH (ORCPT ); Fri, 11 Mar 2011 22:24:07 -0500 Received: by iwn34 with SMTP id 34so3245884iwn.19 for ; Fri, 11 Mar 2011 19:24:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:date:message-id:subject:from:to:cc :content-type; bh=DB2TpumjcB2NCERiq1VD3hX+mYF6RAdOcIi4cdRTaeg=; b=v9he9nNfjSG95DNvXj4h8vW39OtsgCFqZBLAAx0d9I67IrP+y3N9bdey40tMlpxTGa oBk++D+jw4NPgiIDnQr6UuoWT6hXL2GkzBMS20Wc6C9MtDMRwfgS/mZw9u/et60sgiRw CE+X1MxrWAJIepm9GRa5GlYkZ4pwcD5OkTPhk= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:cc:content-type; b=Kn5qMXLEibaj8KMGR3mfnIDUilp06q3LPsWoSZZYkQT+ttoRRWzty/NFmGfhAoQcdJ fbf5+m558ehJmCwW6tv37Kyt73b/x8AO/htGQCnehb1LNrhVekkyK9Yspr1wDes0SiDb u1xynPXHK/WEAMbMzHiZy1wts8QM5Evgf4sEA= MIME-Version: 1.0 Received: by 10.42.145.71 with SMTP id e7mr2512535icv.314.1299900245909; Fri, 11 Mar 2011 19:24:05 -0800 (PST) Received: by 10.42.148.195 with HTTP; Fri, 11 Mar 2011 19:24:05 -0800 (PST) Date: Fri, 11 Mar 2011 21:24:05 -0600 Message-ID: Subject: [PATCH] [CIFS] Allocating SMB2 mids (multiplex identifier structures) From: Steve French To: linux-cifs@vger.kernel.org Cc: Jeff Layton Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Sat, 12 Mar 2011 03:24:09 +0000 (UTC) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 120a9cf..1f489c7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifsfs.c * - * Copyright (C) International Business Machines Corp., 2002,2008 + * Copyright (C) International Business Machines Corp., 2002,2011 * Author(s): Steve French (sfrench@us.ibm.com) * * Common Internet FileSystem (CIFS) client @@ -88,6 +88,11 @@ MODULE_PARM_DESC(sign_zero_copy, "Don't copy pages on write with signing " extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; +#ifdef CONFIG_CIFS_SMB2 +extern mempool_t *smb2_mid_poolp; +mempool_t *smb2_mid_poolp; +static struct kmem_cache *smb2_mid_cachep; +#endif /* CONFIG_CIFS_SMB2 */ void cifs_sb_active(struct super_block *sb) @@ -968,6 +973,25 @@ cifs_init_mids(void) return -ENOMEM; } +#ifdef CONFIG_CIFS_SMB2 + smb2_mid_cachep = kmem_cache_create("smb2_mpx_ids", + sizeof(struct smb2_mid_entry), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (smb2_mid_cachep == NULL) { + mempool_destroy(cifs_mid_poolp); + kmem_cache_destroy(cifs_mid_cachep); + return -ENOMEM; + } + + smb2_mid_poolp = mempool_create_slab_pool(3, smb2_mid_cachep); + if (smb2_mid_poolp == NULL) { + mempool_destroy(cifs_mid_poolp); + kmem_cache_destroy(cifs_mid_cachep); + kmem_cache_destroy(smb2_mid_cachep); + return -ENOMEM; + } +#endif /* CONFIG_CIFS_SMB2 */ + return 0; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d69e1e6..398f596 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -591,20 +591,20 @@ typedef void (mid_callback_t)(struct mid_q_entry *mid); /* one of these for every pending CIFS request to the server */ struct mid_q_entry { struct list_head qhead; /* mids waiting on reply from this server */ - __u16 mid; /* multiplex id */ - __u16 pid; /* process id */ - __u32 sequence_number; /* for CIFS signing */ + int midState; /* wish this were enum but can not pass to wait_event */ unsigned long when_alloc; /* when mid was created */ #ifdef CONFIG_CIFS_STATS2 unsigned long when_sent; /* time when smb send finished */ unsigned long when_received; /* when demux complete (taken off wire) */ #endif + bool largeBuf:1; /* if valid response, is pointer to large buf */ mid_callback_t *callback; /* call completion callback */ void *callback_data; /* general purpose pointer for callback */ + __u16 mid; /* multiplex id */ + __u32 sequence_number; /* for CIFS signing */ + __u8 command; /* smb command code */ + __u16 pid; /* process id */ struct smb_hdr *resp_buf; /* response buffer */ - int midState; /* wish this were enum but can not pass to wait_event */ - __u8 command; /* smb command code */ - bool largeBuf:1; /* if valid response, is pointer to large buf */ bool multiRsp:1; /* multiple trans2 responses for one request */ bool multiEnd:1; /* both received */ }; diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index 66c01db..0093df9 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -160,29 +160,36 @@ struct page_req { struct mid_q_entry *midq; /* queue structure for demultiplex */ }; +struct smb2_mid_entry; + +typedef void (smb2_mid_callback_t)(struct smb2_mid_entry *mid); + /* one of these for every pending SMB2 request to the server */ struct smb2_mid_entry { struct list_head qhead; /* mids waiting on reply from this server */ - __u64 mid; /* multiplex id(s) */ - __u16 pid; /* process id */ - __u32 sequence_number; /* for signing */ /* BB check if needed */ + int mid_state; /* wish this were enum but can not pass to wait_event */ unsigned long when_alloc; /* when mid was created */ #ifdef CONFIG_CIFS_STATS2 unsigned long when_sent; /* time when smb send finished */ unsigned long when_received; /* when demux complete (taken off wire) */ #endif - struct task_struct *tsk; /* task waiting for response */ + bool large_buf:1; /* if valid response, is pointer to large buf */ + smb2_mid_callback_t *callback; + void *callback_data; + __u64 mid; /* multiplex id(s), bigger for smb2 */ + __le16 command; /* smb2 command code */ + __u32 pid; /* process id - bigger for smb2 than cifs */ struct smb2_hdr *resp_buf; /* response buffer */ + + /* Additional fields below needed for handling async smb2 responses + and for asynchronous smb2_writepages support have been temporarily + removed from the port and will be reenabled as that gets merged in */ + +#if 0 /* Fields needed for smb2_writepages, compound ops, async support */ char **pagebuf_list; /* response buffer */ int num_pages; - int mid_state; /* wish this were enum but can not pass to wait_event */ - __le16 command; /* smb command code */ bool async_resp_rcvd:1; /* if server has responded with interim resp */ - bool large_buf:1; /* if valid response, is pointer to large buf */ bool is_kmap_buf:1; -/* bool multi_rsp:1; BB do we have to account for something in SMB2 like - we saw multiple trans2 responses for one request (possible in CIFS) */ - /* Async things */ __u64 *mid_list; /* multiplex id(s) */ int *mid_state_list; short int *large_buf_list; @@ -196,8 +203,7 @@ struct smb2_mid_entry { bool complex_mid:1; /* complex entry - consists of several messages */ int result; unsigned long last_rsp_time; - int (*callback)(struct smb2_mid_entry * , void *); - void *callback_data; +#endif }; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 018d36f..bce3cf9 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -187,8 +187,6 @@ extern int new_read_req(struct kvec *iov, struct cifs_tcon *tcon, const unsigned int count, const __u64 lseek, unsigned int remaining_bytes, int request_type); -extern int allocate_mid(struct cifs_ses *ses, struct smb2_hdr *in_buf, - struct mid_q_entry **ppmidq); extern int smb2_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec); extern int wait_for_free_request(struct cifs_ses *ses, const int long_op); diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 53cf4ec..9d33cd2 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -35,6 +35,8 @@ #include "cifs_debug.h" #include "smb2status.h" +extern mempool_t *smb2_mid_poolp; + /* * Send an (optionally, already signed) SMB2 request over a socket. * This socket is already locked (by a mutex) by the caller so we @@ -137,4 +139,72 @@ smb2_send_complex(const unsigned int xid, struct cifs_ses *ses, return rc; } +static void +wake_up_smb2_task(struct smb2_mid_entry *mid) +{ + wake_up_process(mid->callback_data); +} + +static struct smb2_mid_entry * +smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer, + struct TCP_Server_Info *server) +{ + struct smb2_mid_entry *temp; + + if (server == NULL) { + cERROR(1, "Null TCP session in smb2_mid_entry_alloc"); + return NULL; + } + + temp = mempool_alloc(smb2_mid_poolp, GFP_NOFS); + if (temp == NULL) + return temp; + else { + memset(temp, 0, sizeof(struct smb2_mid_entry)); + temp->mid = smb_buffer->MessageId; /* always LE */ + temp->pid = current->pid; + temp->command = smb_buffer->Command; /* Always LE */ + temp->when_alloc = jiffies; + + /* + * The default is for the mid to be synchronous, so the + * default callback just wakes up the current task. + */ + temp->callback = wake_up_smb2_task; + temp->callback_data = current; + } + + atomic_inc(&midCount); + temp->mid_state = MID_REQUEST_ALLOCATED; + return temp; +} + +static int get_smb2_mid(struct cifs_ses *ses, struct smb2_hdr *in_buf, + struct smb2_mid_entry **ppmidQ) +{ + if (ses->server->tcpStatus == CifsExiting) + return -ENOENT; + + if (ses->server->tcpStatus == CifsNeedReconnect) { + cFYI(1, "tcp session dead - return to caller to retry"); + return -EAGAIN; + } + + if (ses->status != CifsGood) { + /* check if SMB session is bad because we are setting it up */ + if ((in_buf->Command != SMB2_SESSION_SETUP) && + (in_buf->Command != SMB2_NEGOTIATE)) + return -EAGAIN; + /* else ok - we are setting up session */ + } + *ppmidQ = smb2_mid_entry_alloc(in_buf, ses->server); + if (*ppmidQ == NULL) + return -ENOMEM; + spin_lock(&GlobalMid_Lock); + list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q); + spin_unlock(&GlobalMid_Lock); + return 0; +} + +