]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 May 2014 03:20:32 +0000 (12:20 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 May 2014 03:20:32 +0000 (12:20 +0900)
added patches:
cifs-fix-the-race-in-cifs_writev.patch
cifs-wait-for-writebacks-to-complete-before-attempting-write.patch
don-t-bother-with-get-put-_write_access-on-non-regular-files.patch
xen-events-fifo-correctly-align-bitops.patch
xen-spinlock-don-t-enable-them-unconditionally.patch

queue-3.14/cifs-fix-the-race-in-cifs_writev.patch [new file with mode: 0644]
queue-3.14/cifs-wait-for-writebacks-to-complete-before-attempting-write.patch [new file with mode: 0644]
queue-3.14/don-t-bother-with-get-put-_write_access-on-non-regular-files.patch [new file with mode: 0644]
queue-3.14/series
queue-3.14/xen-events-fifo-correctly-align-bitops.patch [new file with mode: 0644]
queue-3.14/xen-spinlock-don-t-enable-them-unconditionally.patch [new file with mode: 0644]

diff --git a/queue-3.14/cifs-fix-the-race-in-cifs_writev.patch b/queue-3.14/cifs-fix-the-race-in-cifs_writev.patch
new file mode 100644 (file)
index 0000000..6889ee4
--- /dev/null
@@ -0,0 +1,64 @@
+From 19dfc1f5f2ef03a52aa30c8257c5745edef23f55 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Thu, 3 Apr 2014 10:27:17 -0400
+Subject: cifs: fix the race in cifs_writev()
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+commit 19dfc1f5f2ef03a52aa30c8257c5745edef23f55 upstream.
+
+O_APPEND handling there hadn't been completely fixed by Pavel's
+patch; it checks the right value, but it's racy - we can't really
+do that until i_mutex has been taken.
+
+Fix by switching to __generic_file_aio_write() (open-coding
+generic_file_aio_write(), actually) and pulling mutex_lock() above
+inode_size_read().
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/cifs/file.c |   23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -2579,19 +2579,32 @@ cifs_writev(struct kiocb *iocb, const st
+       struct cifsInodeInfo *cinode = CIFS_I(inode);
+       struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
+       ssize_t rc = -EACCES;
+-      loff_t lock_pos = pos;
++      loff_t lock_pos = iocb->ki_pos;
+-      if (file->f_flags & O_APPEND)
+-              lock_pos = i_size_read(inode);
+       /*
+        * We need to hold the sem to be sure nobody modifies lock list
+        * with a brlock that prevents writing.
+        */
+       down_read(&cinode->lock_sem);
++      mutex_lock(&inode->i_mutex);
++      if (file->f_flags & O_APPEND)
++              lock_pos = i_size_read(inode);
+       if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs),
+                                    server->vals->exclusive_lock_type, NULL,
+-                                   CIFS_WRITE_OP))
+-              rc = generic_file_aio_write(iocb, iov, nr_segs, pos);
++                                   CIFS_WRITE_OP)) {
++              rc = __generic_file_aio_write(iocb, iov, nr_segs);
++              mutex_unlock(&inode->i_mutex);
++
++              if (rc > 0) {
++                      ssize_t err;
++
++                      err = generic_write_sync(file, iocb->ki_pos - rc, rc);
++                      if (rc < 0)
++                              rc = err;
++              }
++      } else {
++              mutex_unlock(&inode->i_mutex);
++      }
+       up_read(&cinode->lock_sem);
+       return rc;
+ }
diff --git a/queue-3.14/cifs-wait-for-writebacks-to-complete-before-attempting-write.patch b/queue-3.14/cifs-wait-for-writebacks-to-complete-before-attempting-write.patch
new file mode 100644 (file)
index 0000000..a0b2293
--- /dev/null
@@ -0,0 +1,397 @@
+From c11f1df5003d534fd067f0168bfad7befffb3b5c Mon Sep 17 00:00:00 2001
+From: Sachin Prabhu <sprabhu@redhat.com>
+Date: Tue, 11 Mar 2014 16:11:47 +0000
+Subject: cifs: Wait for writebacks to complete before attempting write.
+
+From: Sachin Prabhu <sprabhu@redhat.com>
+
+commit c11f1df5003d534fd067f0168bfad7befffb3b5c upstream.
+
+Problem reported in Red Hat bz 1040329 for strict writes where we cache
+only when we hold oplock and write direct to the server when we don't.
+
+When we receive an oplock break, we first change the oplock value for
+the inode in cifsInodeInfo->oplock to indicate that we no longer hold
+the oplock before we enqueue a task to flush changes to the backing
+device. Once we have completed flushing the changes, we return the
+oplock to the server.
+
+There are 2 ways here where we can have data corruption
+1) While we flush changes to the backing device as part of the oplock
+break, we can have processes write to the file. These writes check for
+the oplock, find none and attempt to write directly to the server.
+These direct writes made while we are flushing from cache could be
+overwritten by data being flushed from the cache causing data
+corruption.
+2) While a thread runs in cifs_strict_writev, the machine could receive
+and process an oplock break after the thread has checked the oplock and
+found that it allows us to cache and before we have made changes to the
+cache. In that case, we end up with a dirty page in cache when we
+shouldn't have any. This will be flushed later and will overwrite all
+subsequent writes to the part of the file represented by this page.
+
+Before making any writes to the server, we need to confirm that we are
+not in the process of flushing data to the server and if we are, we
+should wait until the process is complete before we attempt the write.
+We should also wait for existing writes to complete before we process
+an oplock break request which changes oplock values.
+
+We add a version specific  downgrade_oplock() operation to allow for
+differences in the oplock values set for the different smb versions.
+
+Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
+Reviewed-by: Jeff Layton <jlayton@redhat.com>
+Reviewed-by: Pavel Shilovsky <piastry@etersoft.ru>
+Signed-off-by: Steve French <smfrench@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/cifs/cifsfs.c    |   14 +++++++++
+ fs/cifs/cifsglob.h  |    8 +++++
+ fs/cifs/cifsproto.h |    3 ++
+ fs/cifs/file.c      |   31 +++++++++++++++++++--
+ fs/cifs/misc.c      |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++--
+ fs/cifs/smb1ops.c   |   11 +++++++
+ fs/cifs/smb2misc.c  |   18 ++++++++++--
+ fs/cifs/smb2ops.c   |   14 +++++++++
+ 8 files changed, 164 insertions(+), 9 deletions(-)
+
+--- a/fs/cifs/cifsfs.c
++++ b/fs/cifs/cifsfs.c
+@@ -253,6 +253,11 @@ cifs_alloc_inode(struct super_block *sb)
+       cifs_set_oplock_level(cifs_inode, 0);
+       cifs_inode->delete_pending = false;
+       cifs_inode->invalid_mapping = false;
++      clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cifs_inode->flags);
++      clear_bit(CIFS_INODE_PENDING_WRITERS, &cifs_inode->flags);
++      clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, &cifs_inode->flags);
++      spin_lock_init(&cifs_inode->writers_lock);
++      cifs_inode->writers = 0;
+       cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
+       cifs_inode->server_eof = 0;
+       cifs_inode->uniqueid = 0;
+@@ -731,19 +736,26 @@ static ssize_t cifs_file_aio_write(struc
+                                  unsigned long nr_segs, loff_t pos)
+ {
+       struct inode *inode = file_inode(iocb->ki_filp);
++      struct cifsInodeInfo *cinode = CIFS_I(inode);
+       ssize_t written;
+       int rc;
++      written = cifs_get_writer(cinode);
++      if (written)
++              return written;
++
+       written = generic_file_aio_write(iocb, iov, nr_segs, pos);
+       if (CIFS_CACHE_WRITE(CIFS_I(inode)))
+-              return written;
++              goto out;
+       rc = filemap_fdatawrite(inode->i_mapping);
+       if (rc)
+               cifs_dbg(FYI, "cifs_file_aio_write: %d rc on %p inode\n",
+                        rc, inode);
++out:
++      cifs_put_writer(cinode);
+       return written;
+ }
+--- a/fs/cifs/cifsglob.h
++++ b/fs/cifs/cifsglob.h
+@@ -228,6 +228,8 @@ struct smb_version_operations {
+       /* verify the message */
+       int (*check_message)(char *, unsigned int);
+       bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
++      void (*downgrade_oplock)(struct TCP_Server_Info *,
++                                      struct cifsInodeInfo *, bool);
+       /* process transaction2 response */
+       bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *,
+                            char *, int);
+@@ -1113,6 +1115,12 @@ struct cifsInodeInfo {
+       unsigned int epoch;             /* used to track lease state changes */
+       bool delete_pending;            /* DELETE_ON_CLOSE is set */
+       bool invalid_mapping;           /* pagecache is invalid */
++      unsigned long flags;
++#define CIFS_INODE_PENDING_OPLOCK_BREAK   (0) /* oplock break in progress */
++#define CIFS_INODE_PENDING_WRITERS      (1) /* Writes in progress */
++#define CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2 (2) /* Downgrade oplock to L2 */
++      spinlock_t writers_lock;
++      unsigned int writers;           /* Number of writers on this inode */
+       unsigned long time;             /* jiffies of last update of inode */
+       u64  server_eof;                /* current file size on server -- protected by i_lock */
+       u64  uniqueid;                  /* server inode number */
+--- a/fs/cifs/cifsproto.h
++++ b/fs/cifs/cifsproto.h
+@@ -127,6 +127,9 @@ extern u64 cifs_UnixTimeToNT(struct time
+ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
+                                     int offset);
+ extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
++extern int cifs_get_writer(struct cifsInodeInfo *cinode);
++extern void cifs_put_writer(struct cifsInodeInfo *cinode);
++extern void cifs_done_oplock_break(struct cifsInodeInfo *cinode);
+ extern int cifs_unlock_range(struct cifsFileInfo *cfile,
+                            struct file_lock *flock, const unsigned int xid);
+ extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -2621,12 +2621,20 @@ cifs_strict_writev(struct kiocb *iocb, c
+       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+       ssize_t written;
++      written = cifs_get_writer(cinode);
++      if (written)
++              return written;
++
+       if (CIFS_CACHE_WRITE(cinode)) {
+               if (cap_unix(tcon->ses) &&
+               (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))
+-                  && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+-                      return generic_file_aio_write(iocb, iov, nr_segs, pos);
+-              return cifs_writev(iocb, iov, nr_segs, pos);
++                && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) {
++                      written = generic_file_aio_write(
++                                      iocb, iov, nr_segs, pos);
++                      goto out;
++              }
++              written = cifs_writev(iocb, iov, nr_segs, pos);
++              goto out;
+       }
+       /*
+        * For non-oplocked files in strict cache mode we need to write the data
+@@ -2646,6 +2654,8 @@ cifs_strict_writev(struct kiocb *iocb, c
+                        inode);
+               cinode->oplock = 0;
+       }
++out:
++      cifs_put_writer(cinode);
+       return written;
+ }
+@@ -3657,6 +3667,13 @@ static int cifs_launder_page(struct page
+       return rc;
+ }
++static int
++cifs_pending_writers_wait(void *unused)
++{
++      schedule();
++      return 0;
++}
++
+ void cifs_oplock_break(struct work_struct *work)
+ {
+       struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
+@@ -3664,8 +3681,15 @@ void cifs_oplock_break(struct work_struc
+       struct inode *inode = cfile->dentry->d_inode;
+       struct cifsInodeInfo *cinode = CIFS_I(inode);
+       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
++      struct TCP_Server_Info *server = tcon->ses->server;
+       int rc = 0;
++      wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS,
++                      cifs_pending_writers_wait, TASK_UNINTERRUPTIBLE);
++
++      server->ops->downgrade_oplock(server, cinode,
++              test_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, &cinode->flags));
++
+       if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) &&
+                                               cifs_has_mand_locks(cinode)) {
+               cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n",
+@@ -3702,6 +3726,7 @@ void cifs_oplock_break(struct work_struc
+                                                            cinode);
+               cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
+       }
++      cifs_done_oplock_break(cinode);
+ }
+ /*
+--- a/fs/cifs/misc.c
++++ b/fs/cifs/misc.c
+@@ -466,8 +466,22 @@ is_valid_oplock_break(char *buffer, stru
+                               cifs_dbg(FYI, "file id match, oplock break\n");
+                               pCifsInode = CIFS_I(netfile->dentry->d_inode);
+-                              cifs_set_oplock_level(pCifsInode,
+-                                      pSMB->OplockLevel ? OPLOCK_READ : 0);
++                              set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
++                                      &pCifsInode->flags);
++
++                              /*
++                               * Set flag if the server downgrades the oplock
++                               * to L2 else clear.
++                               */
++                              if (pSMB->OplockLevel)
++                                      set_bit(
++                                         CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
++                                         &pCifsInode->flags);
++                              else
++                                      clear_bit(
++                                         CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
++                                         &pCifsInode->flags);
++
+                               queue_work(cifsiod_wq,
+                                          &netfile->oplock_break);
+                               netfile->oplock_break_cancelled = false;
+@@ -551,6 +565,62 @@ void cifs_set_oplock_level(struct cifsIn
+               cinode->oplock = 0;
+ }
++static int
++cifs_oplock_break_wait(void *unused)
++{
++      schedule();
++      return signal_pending(current) ? -ERESTARTSYS : 0;
++}
++
++/*
++ * We wait for oplock breaks to be processed before we attempt to perform
++ * writes.
++ */
++int cifs_get_writer(struct cifsInodeInfo *cinode)
++{
++      int rc;
++
++start:
++      rc = wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK,
++                                 cifs_oplock_break_wait, TASK_KILLABLE);
++      if (rc)
++              return rc;
++
++      spin_lock(&cinode->writers_lock);
++      if (!cinode->writers)
++              set_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
++      cinode->writers++;
++      /* Check to see if we have started servicing an oplock break */
++      if (test_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags)) {
++              cinode->writers--;
++              if (cinode->writers == 0) {
++                      clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
++                      wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
++              }
++              spin_unlock(&cinode->writers_lock);
++              goto start;
++      }
++      spin_unlock(&cinode->writers_lock);
++      return 0;
++}
++
++void cifs_put_writer(struct cifsInodeInfo *cinode)
++{
++      spin_lock(&cinode->writers_lock);
++      cinode->writers--;
++      if (cinode->writers == 0) {
++              clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
++              wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
++      }
++      spin_unlock(&cinode->writers_lock);
++}
++
++void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
++{
++      clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags);
++      wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK);
++}
++
+ bool
+ backup_cred(struct cifs_sb_info *cifs_sb)
+ {
+--- a/fs/cifs/smb1ops.c
++++ b/fs/cifs/smb1ops.c
+@@ -372,6 +372,16 @@ coalesce_t2(char *second_buf, struct smb
+       return 0;
+ }
++static void
++cifs_downgrade_oplock(struct TCP_Server_Info *server,
++                      struct cifsInodeInfo *cinode, bool set_level2)
++{
++      if (set_level2)
++              cifs_set_oplock_level(cinode, OPLOCK_READ);
++      else
++              cifs_set_oplock_level(cinode, 0);
++}
++
+ static bool
+ cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+                 char *buf, int malformed)
+@@ -1019,6 +1029,7 @@ struct smb_version_operations smb1_opera
+       .clear_stats = cifs_clear_stats,
+       .print_stats = cifs_print_stats,
+       .is_oplock_break = is_valid_oplock_break,
++      .downgrade_oplock = cifs_downgrade_oplock,
+       .check_trans2 = cifs_check_trans2,
+       .need_neg = cifs_need_neg,
+       .negotiate = cifs_negotiate,
+--- a/fs/cifs/smb2misc.c
++++ b/fs/cifs/smb2misc.c
+@@ -575,9 +575,21 @@ smb2_is_valid_oplock_break(char *buffer,
+                               else
+                                       cfile->oplock_break_cancelled = false;
+-                              server->ops->set_oplock_level(cinode,
+-                                rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0,
+-                                0, NULL);
++                              set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
++                                      &cinode->flags);
++
++                              /*
++                               * Set flag if the server downgrades the oplock
++                               * to L2 else clear.
++                               */
++                              if (rsp->OplockLevel)
++                                      set_bit(
++                                         CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
++                                         &cinode->flags);
++                              else
++                                      clear_bit(
++                                         CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
++                                         &cinode->flags);
+                               queue_work(cifsiod_wq, &cfile->oplock_break);
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -905,6 +905,17 @@ smb2_query_symlink(const unsigned int xi
+ }
+ static void
++smb2_downgrade_oplock(struct TCP_Server_Info *server,
++                      struct cifsInodeInfo *cinode, bool set_level2)
++{
++      if (set_level2)
++              server->ops->set_oplock_level(cinode, SMB2_OPLOCK_LEVEL_II,
++                                              0, NULL);
++      else
++              server->ops->set_oplock_level(cinode, 0, 0, NULL);
++}
++
++static void
+ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
+                     unsigned int epoch, bool *purge_cache)
+ {
+@@ -1110,6 +1121,7 @@ struct smb_version_operations smb20_oper
+       .clear_stats = smb2_clear_stats,
+       .print_stats = smb2_print_stats,
+       .is_oplock_break = smb2_is_valid_oplock_break,
++      .downgrade_oplock = smb2_downgrade_oplock,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+       .negotiate_wsize = smb2_negotiate_wsize,
+@@ -1184,6 +1196,7 @@ struct smb_version_operations smb21_oper
+       .clear_stats = smb2_clear_stats,
+       .print_stats = smb2_print_stats,
+       .is_oplock_break = smb2_is_valid_oplock_break,
++      .downgrade_oplock = smb2_downgrade_oplock,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+       .negotiate_wsize = smb2_negotiate_wsize,
+@@ -1259,6 +1272,7 @@ struct smb_version_operations smb30_oper
+       .print_stats = smb2_print_stats,
+       .dump_share_caps = smb2_dump_share_caps,
+       .is_oplock_break = smb2_is_valid_oplock_break,
++      .downgrade_oplock = smb2_downgrade_oplock,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+       .negotiate_wsize = smb2_negotiate_wsize,
diff --git a/queue-3.14/don-t-bother-with-get-put-_write_access-on-non-regular-files.patch b/queue-3.14/don-t-bother-with-get-put-_write_access-on-non-regular-files.patch
new file mode 100644 (file)
index 0000000..de34a2e
--- /dev/null
@@ -0,0 +1,97 @@
+From dd20908a8a06b22c171f6c3fcdbdbd65bed07505 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Fri, 14 Mar 2014 10:56:20 -0400
+Subject: don't bother with {get,put}_write_access() on non-regular files
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+commit dd20908a8a06b22c171f6c3fcdbdbd65bed07505 upstream.
+
+it's pointless and actually leads to wrong behaviour in at least one
+moderately convoluted case (pipe(), close one end, try to get to
+another via /proc/*/fd and run into ETXTBUSY).
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/file_table.c |    4 ++--
+ fs/open.c       |   26 +++++++-------------------
+ 2 files changed, 9 insertions(+), 21 deletions(-)
+
+--- a/fs/file_table.c
++++ b/fs/file_table.c
+@@ -209,10 +209,10 @@ static void drop_file_write_access(struc
+       struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+-      put_write_access(inode);
+-
+       if (special_file(inode->i_mode))
+               return;
++
++      put_write_access(inode);
+       if (file_check_writeable(file) != 0)
+               return;
+       __mnt_drop_write(mnt);
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -641,23 +641,12 @@ out:
+ static inline int __get_file_write_access(struct inode *inode,
+                                         struct vfsmount *mnt)
+ {
+-      int error;
+-      error = get_write_access(inode);
++      int error = get_write_access(inode);
+       if (error)
+               return error;
+-      /*
+-       * Do not take mount writer counts on
+-       * special files since no writes to
+-       * the mount itself will occur.
+-       */
+-      if (!special_file(inode->i_mode)) {
+-              /*
+-               * Balanced in __fput()
+-               */
+-              error = __mnt_want_write(mnt);
+-              if (error)
+-                      put_write_access(inode);
+-      }
++      error = __mnt_want_write(mnt);
++      if (error)
++              put_write_access(inode);
+       return error;
+ }
+@@ -690,12 +679,11 @@ static int do_dentry_open(struct file *f
+       path_get(&f->f_path);
+       inode = f->f_inode = f->f_path.dentry->d_inode;
+-      if (f->f_mode & FMODE_WRITE) {
++      if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) {
+               error = __get_file_write_access(inode, f->f_path.mnt);
+               if (error)
+                       goto cleanup_file;
+-              if (!special_file(inode->i_mode))
+-                      file_take_write(f);
++              file_take_write(f);
+       }
+       f->f_mapping = inode->i_mapping;
+@@ -742,7 +730,6 @@ static int do_dentry_open(struct file *f
+ cleanup_all:
+       fops_put(f->f_op);
+       if (f->f_mode & FMODE_WRITE) {
+-              put_write_access(inode);
+               if (!special_file(inode->i_mode)) {
+                       /*
+                        * We don't consider this a real
+@@ -750,6 +737,7 @@ cleanup_all:
+                        * because it all happenend right
+                        * here, so just reset the state.
+                        */
++                      put_write_access(inode);
+                       file_reset_write(f);
+                       __mnt_drop_write(f->f_path.mnt);
+               }
index b56bd69697f001b7536b712128b352cf713d2e27..625d4a25045b6526f5284e2b8e7185e699db38b6 100644 (file)
@@ -20,3 +20,8 @@ tick-sched-check-tick_nohz_enabled-in-tick_nohz_switch_to_nohz.patch
 parisc-change-value-of-shmlba-from-0x00400000-to-page_size.patch
 parisc-fix-epoll_pwait-syscall-on-compat-kernel.patch
 parisc-remove-_stk_lim_max-override.patch
+don-t-bother-with-get-put-_write_access-on-non-regular-files.patch
+cifs-fix-the-race-in-cifs_writev.patch
+cifs-wait-for-writebacks-to-complete-before-attempting-write.patch
+xen-spinlock-don-t-enable-them-unconditionally.patch
+xen-events-fifo-correctly-align-bitops.patch
diff --git a/queue-3.14/xen-events-fifo-correctly-align-bitops.patch b/queue-3.14/xen-events-fifo-correctly-align-bitops.patch
new file mode 100644 (file)
index 0000000..b94a37f
--- /dev/null
@@ -0,0 +1,138 @@
+From 05a812ac474d0d6aef6d54b66bb08b81abde79c6 Mon Sep 17 00:00:00 2001
+From: Vladimir Murzin <murzin.v@gmail.com>
+Date: Sun, 27 Apr 2014 10:09:12 +0100
+Subject: xen/events/fifo: correctly align bitops
+
+From: Vladimir Murzin <murzin.v@gmail.com>
+
+commit 05a812ac474d0d6aef6d54b66bb08b81abde79c6 upstream.
+
+FIFO event channels require bitops on 32-bit aligned values (the event
+words).  Linux's bitops require unsigned long alignment which may be
+64-bits.
+
+On arm64 an incorrectly unaligned access will fault.
+
+Fix this by aligning the bitops along with an adjustment for bit
+position and using an unsigned long for the local copy of the ready
+word.
+
+Signed-off-by: Vladimir Murzin <murzin.v@gmail.com>
+Tested-by: Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
+Reviewed-by: Ian Campbell <ian.campbell@citrix.com>
+Signed-off-by: David Vrabel <david.vrabel@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/xen/events/events_fifo.c |   41 ++++++++++++++++++++++++++++-----------
+ 1 file changed, 30 insertions(+), 11 deletions(-)
+
+--- a/drivers/xen/events/events_fifo.c
++++ b/drivers/xen/events/events_fifo.c
+@@ -66,7 +66,22 @@ static DEFINE_PER_CPU(struct evtchn_fifo
+ static event_word_t *event_array[MAX_EVENT_ARRAY_PAGES] __read_mostly;
+ static unsigned event_array_pages __read_mostly;
++/*
++ * sync_set_bit() and friends must be unsigned long aligned on non-x86
++ * platforms.
++ */
++#if !defined(CONFIG_X86) && BITS_PER_LONG > 32
++
++#define BM(w) (unsigned long *)((unsigned long)w & ~0x7UL)
++#define EVTCHN_FIFO_BIT(b, w) \
++    (((unsigned long)w & 0x4UL) ? (EVTCHN_FIFO_ ##b + 32) : EVTCHN_FIFO_ ##b)
++
++#else
++
+ #define BM(w) ((unsigned long *)(w))
++#define EVTCHN_FIFO_BIT(b, w) EVTCHN_FIFO_ ##b
++
++#endif
+ static inline event_word_t *event_word_from_port(unsigned port)
+ {
+@@ -161,33 +176,38 @@ static void evtchn_fifo_bind_to_cpu(stru
+ static void evtchn_fifo_clear_pending(unsigned port)
+ {
+       event_word_t *word = event_word_from_port(port);
+-      sync_clear_bit(EVTCHN_FIFO_PENDING, BM(word));
++      sync_clear_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
+ }
+ static void evtchn_fifo_set_pending(unsigned port)
+ {
+       event_word_t *word = event_word_from_port(port);
+-      sync_set_bit(EVTCHN_FIFO_PENDING, BM(word));
++      sync_set_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
+ }
+ static bool evtchn_fifo_is_pending(unsigned port)
+ {
+       event_word_t *word = event_word_from_port(port);
+-      return sync_test_bit(EVTCHN_FIFO_PENDING, BM(word));
++      return sync_test_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
+ }
+ static bool evtchn_fifo_test_and_set_mask(unsigned port)
+ {
+       event_word_t *word = event_word_from_port(port);
+-      return sync_test_and_set_bit(EVTCHN_FIFO_MASKED, BM(word));
++      return sync_test_and_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
+ }
+ static void evtchn_fifo_mask(unsigned port)
+ {
+       event_word_t *word = event_word_from_port(port);
+-      sync_set_bit(EVTCHN_FIFO_MASKED, BM(word));
++      sync_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
+ }
++static bool evtchn_fifo_is_masked(unsigned port)
++{
++      event_word_t *word = event_word_from_port(port);
++      return sync_test_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
++}
+ /*
+  * Clear MASKED, spinning if BUSY is set.
+  */
+@@ -211,7 +231,7 @@ static void evtchn_fifo_unmask(unsigned
+       BUG_ON(!irqs_disabled());
+       clear_masked(word);
+-      if (sync_test_bit(EVTCHN_FIFO_PENDING, BM(word))) {
++      if (evtchn_fifo_is_pending(port)) {
+               struct evtchn_unmask unmask = { .port = port };
+               (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
+       }
+@@ -247,7 +267,7 @@ static void handle_irq_for_port(unsigned
+ static void consume_one_event(unsigned cpu,
+                             struct evtchn_fifo_control_block *control_block,
+-                            unsigned priority, uint32_t *ready)
++                            unsigned priority, unsigned long *ready)
+ {
+       struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
+       uint32_t head;
+@@ -277,10 +297,9 @@ static void consume_one_event(unsigned c
+        * copy of the ready word.
+        */
+       if (head == 0)
+-              clear_bit(priority, BM(ready));
++              clear_bit(priority, ready);
+-      if (sync_test_bit(EVTCHN_FIFO_PENDING, BM(word))
+-          && !sync_test_bit(EVTCHN_FIFO_MASKED, BM(word)))
++      if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port))
+               handle_irq_for_port(port);
+       q->head[priority] = head;
+@@ -289,7 +308,7 @@ static void consume_one_event(unsigned c
+ static void evtchn_fifo_handle_events(unsigned cpu)
+ {
+       struct evtchn_fifo_control_block *control_block;
+-      uint32_t ready;
++      unsigned long ready;
+       unsigned q;
+       control_block = per_cpu(cpu_control_block, cpu);
diff --git a/queue-3.14/xen-spinlock-don-t-enable-them-unconditionally.patch b/queue-3.14/xen-spinlock-don-t-enable-them-unconditionally.patch
new file mode 100644 (file)
index 0000000..b2b62d7
--- /dev/null
@@ -0,0 +1,53 @@
+From e0fc17a936334c08b2729fff87168c03fdecf5b6 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Date: Fri, 4 Apr 2014 14:48:04 -0400
+Subject: xen/spinlock: Don't enable them unconditionally.
+
+From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+
+commit e0fc17a936334c08b2729fff87168c03fdecf5b6 upstream.
+
+The git commit a945928ea2709bc0e8e8165d33aed855a0110279
+('xen: Do not enable spinlocks before jump_label_init() has executed')
+was added to deal with the jump machinery. Earlier the code
+that turned on the jump label was only called by Xen specific
+functions. But now that it had been moved to the initcall machinery
+it gets called on Xen, KVM, and baremetal - ouch!. And the detection
+machinery to only call it on Xen wasn't remembered in the heat
+of merge window excitement.
+
+This means that the slowpath is enabled on baremetal while it should
+not be.
+
+Reported-by: Waiman Long <waiman.long@hp.com>
+Acked-by: Steven Rostedt <rostedt@goodmis.org>
+CC: Boris Ostrovsky <boris.ostrovsky@oracle.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+Signed-off-by: David Vrabel <david.vrabel@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/xen/spinlock.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/xen/spinlock.c
++++ b/arch/x86/xen/spinlock.c
+@@ -274,7 +274,7 @@ void __init xen_init_spinlocks(void)
+               printk(KERN_DEBUG "xen: PV spinlocks disabled\n");
+               return;
+       }
+-
++      printk(KERN_DEBUG "xen: PV spinlocks enabled\n");
+       pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(xen_lock_spinning);
+       pv_lock_ops.unlock_kick = xen_unlock_kick;
+ }
+@@ -290,6 +290,9 @@ static __init int xen_init_spinlocks_jum
+       if (!xen_pvspin)
+               return 0;
++      if (!xen_domain())
++              return 0;
++
+       static_key_slow_inc(&paravirt_ticketlocks_enabled);
+       return 0;
+ }