From: Greg Kroah-Hartman Date: Tue, 20 May 2014 03:20:32 +0000 (+0900) Subject: 3.14-stable patches X-Git-Tag: v3.10.41~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a0a75ed8ea9e7cfece29963d1009cbfbac7044b2;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches 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 --- 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 index 00000000000..6889ee4863b --- /dev/null +++ b/queue-3.14/cifs-fix-the-race-in-cifs_writev.patch @@ -0,0 +1,64 @@ +From 19dfc1f5f2ef03a52aa30c8257c5745edef23f55 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Thu, 3 Apr 2014 10:27:17 -0400 +Subject: cifs: fix the race in cifs_writev() + +From: Al Viro + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..a0b22939d83 --- /dev/null +++ b/queue-3.14/cifs-wait-for-writebacks-to-complete-before-attempting-write.patch @@ -0,0 +1,397 @@ +From c11f1df5003d534fd067f0168bfad7befffb3b5c Mon Sep 17 00:00:00 2001 +From: Sachin Prabhu +Date: Tue, 11 Mar 2014 16:11:47 +0000 +Subject: cifs: Wait for writebacks to complete before attempting write. + +From: Sachin Prabhu + +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 +Reviewed-by: Jeff Layton +Reviewed-by: Pavel Shilovsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..de34a2e152b --- /dev/null +++ b/queue-3.14/don-t-bother-with-get-put-_write_access-on-non-regular-files.patch @@ -0,0 +1,97 @@ +From dd20908a8a06b22c171f6c3fcdbdbd65bed07505 Mon Sep 17 00:00:00 2001 +From: Al Viro +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 + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + } diff --git a/queue-3.14/series b/queue-3.14/series index b56bd69697f..625d4a25045 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -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 index 00000000000..b94a37fc154 --- /dev/null +++ b/queue-3.14/xen-events-fifo-correctly-align-bitops.patch @@ -0,0 +1,138 @@ +From 05a812ac474d0d6aef6d54b66bb08b81abde79c6 Mon Sep 17 00:00:00 2001 +From: Vladimir Murzin +Date: Sun, 27 Apr 2014 10:09:12 +0100 +Subject: xen/events/fifo: correctly align bitops + +From: Vladimir Murzin + +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 +Tested-by: Pranavkumar Sawargaonkar +Reviewed-by: Ian Campbell +Signed-off-by: David Vrabel +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..b2b62d73b70 --- /dev/null +++ b/queue-3.14/xen-spinlock-don-t-enable-them-unconditionally.patch @@ -0,0 +1,53 @@ +From e0fc17a936334c08b2729fff87168c03fdecf5b6 Mon Sep 17 00:00:00 2001 +From: Konrad Rzeszutek Wilk +Date: Fri, 4 Apr 2014 14:48:04 -0400 +Subject: xen/spinlock: Don't enable them unconditionally. + +From: Konrad Rzeszutek Wilk + +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 +Acked-by: Steven Rostedt +CC: Boris Ostrovsky +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: David Vrabel +Signed-off-by: Greg Kroah-Hartman + +--- + 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(¶virt_ticketlocks_enabled); + return 0; + }