summaryrefslogtreecommitdiff
path: root/fs/cifs/cifssmb.c
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2012-07-25 23:58:48 +0400
committerJeff Garzik <jgarzik@redhat.com>2012-07-25 23:58:48 +0400
commit8407884dd9164ec18ed2afc00f56b87e36c51fcf (patch)
treeb6ea42c231d7d39f454de28a068d78ce11709770 /fs/cifs/cifssmb.c
parentdc7f71f486f4f5fa96f6dcf86833da020cde8a11 (diff)
parentbdc0077af574800d24318b6945cf2344e8dbb050 (diff)
downloadlinux-8407884dd9164ec18ed2afc00f56b87e36c51fcf.tar.xz
Merge branch 'master' [vanilla Linus master] into libata-dev.git/upstream
Two bits were appended to the end of the bitfield list in struct scsi_device. Resolve that conflict by including both bits. Conflicts: include/scsi/scsi_device.h
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r--fs/cifs/cifssmb.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 5b400730c213..4ee522b3f66f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -86,7 +86,31 @@ static struct {
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
#endif /* CIFS_POSIX */
-/* Forward declarations */
+#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 */
@@ -1503,7 +1527,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
}
/* marshal up the page array */
+ cifs_kmap_lock();
len = rdata->marshal_iov(rdata, data_len);
+ cifs_kmap_unlock();
data_len -= len;
/* issue the read if we have any iovecs left to fill */
@@ -2069,7 +2095,9 @@ cifs_async_writev(struct cifs_writedata *wdata)
* and set the iov_len properly for each one. It may also set
* wdata->bytes too.
*/
+ cifs_kmap_lock();
wdata->marshal_iov(iov, wdata);
+ cifs_kmap_unlock();
cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);