sparc: tsb must be flushed before tlb
[pandora-kernel.git] / fs / cifs / cifssmb.c
index 6600aa2..c858a29 100644 (file)
@@ -89,6 +89,32 @@ static struct {
 /* Forward declarations */
 static void cifs_readv_complete(struct work_struct *work);
 
+#ifdef CONFIG_HIGHMEM
+/*
+ * On arches that have high memory, kmap address space is limited. By
+ * serializing the kmap operations on those arches, we ensure that we don't
+ * end up with a bunch of threads in writeback with partially mapped page
+ * arrays, stuck waiting for kmap to come back. That situation prevents
+ * progress and can deadlock.
+ */
+static DEFINE_MUTEX(cifs_kmap_mutex);
+
+static inline void
+cifs_kmap_lock(void)
+{
+       mutex_lock(&cifs_kmap_mutex);
+}
+
+static inline void
+cifs_kmap_unlock(void)
+{
+       mutex_unlock(&cifs_kmap_mutex);
+}
+#else /* !CONFIG_HIGHMEM */
+#define cifs_kmap_lock() do { ; } while(0)
+#define cifs_kmap_unlock() do { ; } while(0)
+#endif /* CONFIG_HIGHMEM */
+
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
 static void mark_open_files_invalid(struct cifs_tcon *pTcon)
@@ -458,7 +484,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
                        goto neg_err_exit;
                }
                server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
-               server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+               server->maxReq = min_t(unsigned int,
+                                      le16_to_cpu(rsp->MaxMpxCount),
+                                      cifs_max_pending);
+               server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
                server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
                server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
                /* even though we do not use raw we might as well set this
@@ -564,7 +593,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 
        /* one byte, so no need to convert this or EncryptionKeyLen from
           little endian */
-       server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+       server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
+                              cifs_max_pending);
+       server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
        /* probably no need to store and check maxvcs */
        server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
        server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
@@ -1535,6 +1566,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
        cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
 
+       cifs_kmap_lock();
        list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
                if (remaining >= PAGE_CACHE_SIZE) {
                        /* enough data to fill the page */
@@ -1584,6 +1616,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
                        page_cache_release(page);
                }
        }
+       cifs_kmap_unlock();
 
        /* issue the read if we have any iovecs left to fill */
        if (rdata->nr_iov > 1) {
@@ -2166,6 +2199,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
        iov[0].iov_base = smb;
 
        /* marshal up the pages into iov array */
+       cifs_kmap_lock();
        wdata->bytes = 0;
        for (i = 0; i < wdata->nr_pages; i++) {
                iov[i + 1].iov_len = min(inode->i_size -
@@ -2174,6 +2208,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
                iov[i + 1].iov_base = kmap(wdata->pages[i]);
                wdata->bytes += iov[i + 1].iov_len;
        }
+       cifs_kmap_unlock();
 
        cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
 
@@ -4322,7 +4357,7 @@ int
 CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
              const char *searchName,
              const struct nls_table *nls_codepage,
-             __u16 *pnetfid,
+             __u16 *pnetfid, __u16 search_flags,
              struct cifs_search_info *psrch_inf, int remap, const char dirsep)
 {
 /* level 257 SMB_ */
@@ -4394,8 +4429,7 @@ findFirstRetry:
            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
                        ATTR_DIRECTORY);
        pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
-       pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
-               CIFS_SEARCH_RETURN_RESUME);
+       pSMB->SearchFlags = cpu_to_le16(search_flags);
        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
 
        /* BB what should we set StorageType to? Does it matter? BB */
@@ -4465,8 +4499,8 @@ findFirstRetry:
        return rc;
 }
 
-int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
-                __u16 searchHandle, struct cifs_search_info *psrch_inf)
+int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
+                __u16 search_flags, struct cifs_search_info *psrch_inf)
 {
        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
@@ -4509,8 +4543,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
                cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
        pSMB->ResumeKey = psrch_inf->resume_key;
-       pSMB->SearchFlags =
-             cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
+       pSMB->SearchFlags = cpu_to_le16(search_flags);
 
        name_len = psrch_inf->resume_name_len;
        params += name_len;
@@ -4821,8 +4854,12 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
                max_len = data_end - temp;
                node->node_name = cifs_strndup_from_ucs(temp, max_len,
                                                      is_unicode, nls_codepage);
-               if (!node->node_name)
+               if (!node->node_name) {
                        rc = -ENOMEM;
+                       goto parse_DFS_referrals_exit;
+               }
+
+               ref++;
        }
 
 parse_DFS_referrals_exit: