diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-02 11:44:07 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-02 11:44:07 -0700 |
commit | 0d1514e0157dd89564045969f05e3e0b5f4ddf8d (patch) | |
tree | 64433d52cce48695aa8c56aa4decca929169a7cc | |
parent | 74d959235354de64ad327d4952c65048bd09c067 (diff) | |
download | stable-queue-0d1514e0157dd89564045969f05e3e0b5f4ddf8d.tar.gz |
3.0 patches
13 files changed, 998 insertions, 0 deletions
diff --git a/queue-3.0/ecryptfs-make-inode-bdi-consistent-with-superblock-bdi.patch b/queue-3.0/ecryptfs-make-inode-bdi-consistent-with-superblock-bdi.patch new file mode 100644 index 0000000000..0f4039d7a6 --- /dev/null +++ b/queue-3.0/ecryptfs-make-inode-bdi-consistent-with-superblock-bdi.patch @@ -0,0 +1,30 @@ +From 985ca0e626e195ea08a1a82b8dbeb6719747429a Mon Sep 17 00:00:00 2001 +From: Thieu Le <thieule@chromium.org> +Date: Tue, 26 Jul 2011 16:15:10 -0700 +Subject: ecryptfs: Make inode bdi consistent with superblock bdi + +From: Thieu Le <thieule@chromium.org> + +commit 985ca0e626e195ea08a1a82b8dbeb6719747429a upstream. + +Make the inode mapping bdi consistent with the superblock bdi so that +dirty pages are flushed properly. + +Signed-off-by: Thieu Le <thieule@chromium.org> +Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/ecryptfs/inode.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/ecryptfs/inode.c ++++ b/fs/ecryptfs/inode.c +@@ -69,6 +69,7 @@ static int ecryptfs_inode_set(struct ino + inode->i_ino = lower_inode->i_ino; + inode->i_version++; + inode->i_mapping->a_ops = &ecryptfs_aops; ++ inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi; + + if (S_ISLNK(inode->i_mode)) + inode->i_op = &ecryptfs_symlink_iops; diff --git a/queue-3.0/ecryptfs-unlock-keys-needed-by-ecryptfsd.patch b/queue-3.0/ecryptfs-unlock-keys-needed-by-ecryptfsd.patch new file mode 100644 index 0000000000..f99f0ff704 --- /dev/null +++ b/queue-3.0/ecryptfs-unlock-keys-needed-by-ecryptfsd.patch @@ -0,0 +1,180 @@ +From b2987a5e05ec7a1af7ca42e5d5349d7a22753031 Mon Sep 17 00:00:00 2001 +From: Tyler Hicks <tyhicks@linux.vnet.ibm.com> +Date: Tue, 26 Jul 2011 19:47:08 -0500 +Subject: eCryptfs: Unlock keys needed by ecryptfsd + +From: Tyler Hicks <tyhicks@linux.vnet.ibm.com> + +commit b2987a5e05ec7a1af7ca42e5d5349d7a22753031 upstream. + +Fixes a regression caused by b5695d04634fa4ccca7dcbc05bb4a66522f02e0b + +Kernel keyring keys containing eCryptfs authentication tokens should not +be write locked when calling out to ecryptfsd to wrap and unwrap file +encryption keys. The eCryptfs kernel code can not hold the key's write +lock because ecryptfsd needs to request the key after receiving such a +request from the kernel. + +Without this fix, all file opens and creates will timeout and fail when +using the eCryptfs PKI infrastructure. This is not an issue when using +passphrase-based mount keys, which is the most widely deployed eCryptfs +configuration. + +Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com> +Acked-by: Roberto Sassu <roberto.sassu@polito.it> +Tested-by: Roberto Sassu <roberto.sassu@polito.it> +Tested-by: Alexis Hafner1 <haf@zurich.ibm.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/ecryptfs/keystore.c | 47 +++++++++++++++++++++++++---------------------- + 1 file changed, 25 insertions(+), 22 deletions(-) + +--- a/fs/ecryptfs/keystore.c ++++ b/fs/ecryptfs/keystore.c +@@ -1868,11 +1868,6 @@ int ecryptfs_parse_packet_set(struct ecr + * just one will be sufficient to decrypt to get the FEK. */ + find_next_matching_auth_tok: + found_auth_tok = 0; +- if (auth_tok_key) { +- up_write(&(auth_tok_key->sem)); +- key_put(auth_tok_key); +- auth_tok_key = NULL; +- } + list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) { + candidate_auth_tok = &auth_tok_list_item->auth_tok; + if (unlikely(ecryptfs_verbosity > 0)) { +@@ -1909,14 +1904,22 @@ found_matching_auth_tok: + memcpy(&(candidate_auth_tok->token.private_key), + &(matching_auth_tok->token.private_key), + sizeof(struct ecryptfs_private_key)); ++ up_write(&(auth_tok_key->sem)); ++ key_put(auth_tok_key); + rc = decrypt_pki_encrypted_session_key(candidate_auth_tok, + crypt_stat); + } else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) { + memcpy(&(candidate_auth_tok->token.password), + &(matching_auth_tok->token.password), + sizeof(struct ecryptfs_password)); ++ up_write(&(auth_tok_key->sem)); ++ key_put(auth_tok_key); + rc = decrypt_passphrase_encrypted_session_key( + candidate_auth_tok, crypt_stat); ++ } else { ++ up_write(&(auth_tok_key->sem)); ++ key_put(auth_tok_key); ++ rc = -EINVAL; + } + if (rc) { + struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp; +@@ -1956,15 +1959,12 @@ found_matching_auth_tok: + out_wipe_list: + wipe_auth_tok_list(&auth_tok_list); + out: +- if (auth_tok_key) { +- up_write(&(auth_tok_key->sem)); +- key_put(auth_tok_key); +- } + return rc; + } + + static int +-pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok, ++pki_encrypt_session_key(struct key *auth_tok_key, ++ struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_key_record *key_rec) + { +@@ -1979,6 +1979,8 @@ pki_encrypt_session_key(struct ecryptfs_ + crypt_stat->cipher, + crypt_stat->key_size), + crypt_stat, &payload, &payload_len); ++ up_write(&(auth_tok_key->sem)); ++ key_put(auth_tok_key); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n"); + goto out; +@@ -2008,6 +2010,8 @@ out: + * write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet + * @dest: Buffer into which to write the packet + * @remaining_bytes: Maximum number of bytes that can be writtn ++ * @auth_tok_key: The authentication token key to unlock and put when done with ++ * @auth_tok + * @auth_tok: The authentication token used for generating the tag 1 packet + * @crypt_stat: The cryptographic context + * @key_rec: The key record struct for the tag 1 packet +@@ -2018,7 +2022,7 @@ out: + */ + static int + write_tag_1_packet(char *dest, size_t *remaining_bytes, +- struct ecryptfs_auth_tok *auth_tok, ++ struct key *auth_tok_key, struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_key_record *key_rec, size_t *packet_size) + { +@@ -2039,12 +2043,15 @@ write_tag_1_packet(char *dest, size_t *r + memcpy(key_rec->enc_key, + auth_tok->session_key.encrypted_key, + auth_tok->session_key.encrypted_key_size); ++ up_write(&(auth_tok_key->sem)); ++ key_put(auth_tok_key); + goto encrypted_session_key_set; + } + if (auth_tok->session_key.encrypted_key_size == 0) + auth_tok->session_key.encrypted_key_size = + auth_tok->token.private_key.key_size; +- rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec); ++ rc = pki_encrypt_session_key(auth_tok_key, auth_tok, crypt_stat, ++ key_rec); + if (rc) { + printk(KERN_ERR "Failed to encrypt session key via a key " + "module; rc = [%d]\n", rc); +@@ -2421,6 +2428,8 @@ ecryptfs_generate_key_packet_set(char *d + &max, auth_tok, + crypt_stat, key_rec, + &written); ++ up_write(&(auth_tok_key->sem)); ++ key_put(auth_tok_key); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error " + "writing tag 3 packet\n"); +@@ -2438,8 +2447,8 @@ ecryptfs_generate_key_packet_set(char *d + } + (*len) += written; + } else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) { +- rc = write_tag_1_packet(dest_base + (*len), +- &max, auth_tok, ++ rc = write_tag_1_packet(dest_base + (*len), &max, ++ auth_tok_key, auth_tok, + crypt_stat, key_rec, &written); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error " +@@ -2448,14 +2457,13 @@ ecryptfs_generate_key_packet_set(char *d + } + (*len) += written; + } else { ++ up_write(&(auth_tok_key->sem)); ++ key_put(auth_tok_key); + ecryptfs_printk(KERN_WARNING, "Unsupported " + "authentication token type\n"); + rc = -EINVAL; + goto out_free; + } +- up_write(&(auth_tok_key->sem)); +- key_put(auth_tok_key); +- auth_tok_key = NULL; + } + if (likely(max > 0)) { + dest_base[(*len)] = 0x00; +@@ -2468,11 +2476,6 @@ out_free: + out: + if (rc) + (*len) = 0; +- if (auth_tok_key) { +- up_write(&(auth_tok_key->sem)); +- key_put(auth_tok_key); +- } +- + mutex_unlock(&crypt_stat->keysig_list_mutex); + return rc; + } diff --git a/queue-3.0/ehci-fix-direction-handling-for-interrupt-data-toggles.patch b/queue-3.0/ehci-fix-direction-handling-for-interrupt-data-toggles.patch new file mode 100644 index 0000000000..9287fab11f --- /dev/null +++ b/queue-3.0/ehci-fix-direction-handling-for-interrupt-data-toggles.patch @@ -0,0 +1,72 @@ +From e04f5f7e423018bcec84c11af2058cdce87816f3 Mon Sep 17 00:00:00 2001 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 19 Jul 2011 14:01:23 -0400 +Subject: EHCI: fix direction handling for interrupt data toggles + +From: Alan Stern <stern@rowland.harvard.edu> + +commit e04f5f7e423018bcec84c11af2058cdce87816f3 upstream. + +This patch (as1480) fixes a rather obscure bug in ehci-hcd. The +qh_update() routine needs to know the number and direction of the +endpoint corresponding to its QH argument. The number can be taken +directly from the QH data structure, but the direction isn't stored +there. The direction is taken instead from the first qTD linked to +the QH. + +However, it turns out that for interrupt transfers, qh_update() gets +called before the qTDs are linked to the QH. As a result, qh_update() +computes a bogus direction value, which messes up the endpoint toggle +handling. Under the right combination of circumstances this causes +usb_reset_endpoint() not to work correctly, which causes packets to be +dropped and communications to fail. + +Now, it's silly for the QH structure not to have direct access to all +the descriptor information for the corresponding endpoint. Ultimately +it may get a pointer to the usb_host_endpoint structure; for now, +adding a copy of the direction flag solves the immediate problem. + +This allows the Spyder2 color-calibration system (a low-speed USB +device that sends all its interrupt data packets with the toggle set +to 0 and hance requires constant use of usb_reset_endpoint) to work +when connected through a high-speed hub. Thanks to Graeme Gill for +supplying the hardware that allowed me to track down this bug. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Reported-by: Graeme Gill <graeme@argyllcms.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/ehci-q.c | 3 ++- + drivers/usb/host/ehci.h | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/ehci-q.c ++++ b/drivers/usb/host/ehci-q.c +@@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct + if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { + unsigned is_out, epnum; + +- is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); ++ is_out = qh->is_out; + epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; + if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { + hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); +@@ -946,6 +946,7 @@ done: + hw = qh->hw; + hw->hw_info1 = cpu_to_hc32(ehci, info1); + hw->hw_info2 = cpu_to_hc32(ehci, info2); ++ qh->is_out = !is_input; + usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); + qh_refresh (ehci, qh); + return qh; +--- a/drivers/usb/host/ehci.h ++++ b/drivers/usb/host/ehci.h +@@ -375,6 +375,7 @@ struct ehci_qh { + #define NO_FRAME ((unsigned short)~0) /* pick new start */ + + struct usb_device *dev; /* access to TT */ ++ unsigned is_out:1; /* bulk or intr OUT */ + unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ + }; + diff --git a/queue-3.0/ehci-only-power-off-port-if-over-current-is-active.patch b/queue-3.0/ehci-only-power-off-port-if-over-current-is-active.patch new file mode 100644 index 0000000000..d50bbe4dea --- /dev/null +++ b/queue-3.0/ehci-only-power-off-port-if-over-current-is-active.patch @@ -0,0 +1,43 @@ +From 81463c1d707186adbbe534016cd1249edeab0dac Mon Sep 17 00:00:00 2001 +From: Sergei Shtylyov <sshtylyov@ru.mvista.com> +Date: Wed, 6 Jul 2011 23:19:38 +0400 +Subject: EHCI: only power off port if over-current is active + +From: Sergei Shtylyov <sshtylyov@ru.mvista.com> + +commit 81463c1d707186adbbe534016cd1249edeab0dac upstream. + +MAX4967 USB power supply chip we use on our boards signals over-current when +power is not enabled; once it's enabled, over-current signal returns to normal. +That unfortunately caused the endless stream of "over-current change on port" +messages. The EHCI root hub code reacts on every over-current signal change +with powering off the port -- such change event is generated the moment the +port power is enabled, so once enabled the power is immediately cut off. +I think we should only cut off power when we're seeing the active over-current +signal, so I'm adding such check to that code. I also think that the fact that +we've cut off the port power should be reflected in the result of GetPortStatus +request immediately, hence I'm adding a PORTSCn register readback after write... + +Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> +Acked-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/ehci-hub.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -891,10 +891,11 @@ static int ehci_hub_control ( + * power switching; they're allowed to just limit the + * current. khubd will turn the power back on. + */ +- if (HCS_PPC (ehci->hcs_params)){ ++ if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) { + ehci_writel(ehci, + temp & ~(PORT_RWC_BITS | PORT_POWER), + status_reg); ++ temp = ehci_readl(ehci, status_reg); + } + } + diff --git a/queue-3.0/n_gsm-fix-the-wrong-fcs-handling.patch b/queue-3.0/n_gsm-fix-the-wrong-fcs-handling.patch new file mode 100644 index 0000000000..b6103c0d60 --- /dev/null +++ b/queue-3.0/n_gsm-fix-the-wrong-fcs-handling.patch @@ -0,0 +1,36 @@ +From f086ced17191fa0c5712539d2b680eae3dc972a1 Mon Sep 17 00:00:00 2001 +From: "Du, Alek" <alek.du@intel.com> +Date: Thu, 7 Jul 2011 15:16:48 +0100 +Subject: n_gsm: fix the wrong FCS handling + +From: "Du, Alek" <alek.du@intel.com> + +commit f086ced17191fa0c5712539d2b680eae3dc972a1 upstream. + +FCS could be GSM0_SOF, so will break state machine... + +[This byte isn't quoted in any way so a SOF here doesn't imply an error + occurred.] + +Signed-off-by: Alek Du <alek.du@intel.com> +Signed-off-by: Alan Cox <alan@linux.intel.com> +[Trivial but best backported once its in 3.1rc I think] +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/tty/n_gsm.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -1823,10 +1823,6 @@ static void gsm0_receive(struct gsm_mux + break; + case GSM_FCS: /* FCS follows the packet */ + gsm->received_fcs = c; +- if (c == GSM0_SOF) { +- gsm->state = GSM_SEARCH; +- break; +- } + gsm_queue(gsm); + gsm->state = GSM_SSOF; + break; diff --git a/queue-3.0/nfs-fix-spurious-readdir-cookie-loop-messages.patch b/queue-3.0/nfs-fix-spurious-readdir-cookie-loop-messages.patch new file mode 100644 index 0000000000..741655119c --- /dev/null +++ b/queue-3.0/nfs-fix-spurious-readdir-cookie-loop-messages.patch @@ -0,0 +1,183 @@ +From 0c0308066ca53fdf1423895f3a42838b67b3a5a8 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust <Trond.Myklebust@netapp.com> +Date: Sat, 30 Jul 2011 12:45:35 -0400 +Subject: NFS: Fix spurious readdir cookie loop messages + +From: Trond Myklebust <Trond.Myklebust@netapp.com> + +commit 0c0308066ca53fdf1423895f3a42838b67b3a5a8 upstream. + +If the directory contents change, then we have to accept that the +file->f_pos value may shrink if we do a 'search-by-cookie'. In that +case, we should turn off the loop detection and let the NFS client +try to recover. + +The patch also fixes a second loop detection bug by ensuring +that after turning on the ctx->duped flag, we read at least one new +cookie into ctx->dir_cookie before attempting to match with +ctx->dup_cookie. + +Reported-by: Petr Vandrovec <petr@vandrovec.name> +Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/nfs/dir.c | 56 ++++++++++++++++++++++++++++--------------------- + include/linux/nfs_fs.h | 3 +- + 2 files changed, 35 insertions(+), 24 deletions(-) + +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -134,18 +134,19 @@ const struct inode_operations nfs4_dir_i + + #endif /* CONFIG_NFS_V4 */ + +-static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred) ++static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) + { + struct nfs_open_dir_context *ctx; + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + if (ctx != NULL) { + ctx->duped = 0; ++ ctx->attr_gencount = NFS_I(dir)->attr_gencount; + ctx->dir_cookie = 0; + ctx->dup_cookie = 0; + ctx->cred = get_rpccred(cred); +- } else +- ctx = ERR_PTR(-ENOMEM); +- return ctx; ++ return ctx; ++ } ++ return ERR_PTR(-ENOMEM); + } + + static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) +@@ -173,7 +174,7 @@ nfs_opendir(struct inode *inode, struct + cred = rpc_lookup_cred(); + if (IS_ERR(cred)) + return PTR_ERR(cred); +- ctx = alloc_nfs_open_dir_context(cred); ++ ctx = alloc_nfs_open_dir_context(inode, cred); + if (IS_ERR(ctx)) { + res = PTR_ERR(ctx); + goto out; +@@ -323,7 +324,6 @@ int nfs_readdir_search_for_pos(struct nf + { + loff_t diff = desc->file->f_pos - desc->current_index; + unsigned int index; +- struct nfs_open_dir_context *ctx = desc->file->private_data; + + if (diff < 0) + goto out_eof; +@@ -336,7 +336,6 @@ int nfs_readdir_search_for_pos(struct nf + index = (unsigned int)diff; + *desc->dir_cookie = array->array[index].cookie; + desc->cache_entry_index = index; +- ctx->duped = 0; + return 0; + out_eof: + desc->eof = 1; +@@ -349,14 +348,33 @@ int nfs_readdir_search_for_cookie(struct + int i; + loff_t new_pos; + int status = -EAGAIN; +- struct nfs_open_dir_context *ctx = desc->file->private_data; + + for (i = 0; i < array->size; i++) { + if (array->array[i].cookie == *desc->dir_cookie) { ++ struct nfs_inode *nfsi = NFS_I(desc->file->f_path.dentry->d_inode); ++ struct nfs_open_dir_context *ctx = desc->file->private_data; ++ + new_pos = desc->current_index + i; +- if (new_pos < desc->file->f_pos) { ++ if (ctx->attr_gencount != nfsi->attr_gencount ++ || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) { ++ ctx->duped = 0; ++ ctx->attr_gencount = nfsi->attr_gencount; ++ } else if (new_pos < desc->file->f_pos) { ++ if (ctx->duped > 0 ++ && ctx->dup_cookie == *desc->dir_cookie) { ++ if (printk_ratelimit()) { ++ pr_notice("NFS: directory %s/%s contains a readdir loop." ++ "Please contact your server vendor. " ++ "Offending cookie: %llu\n", ++ desc->file->f_dentry->d_parent->d_name.name, ++ desc->file->f_dentry->d_name.name, ++ *desc->dir_cookie); ++ } ++ status = -ELOOP; ++ goto out; ++ } + ctx->dup_cookie = *desc->dir_cookie; +- ctx->duped = 1; ++ ctx->duped = -1; + } + desc->file->f_pos = new_pos; + desc->cache_entry_index = i; +@@ -368,6 +386,7 @@ int nfs_readdir_search_for_cookie(struct + if (*desc->dir_cookie == array->last_cookie) + desc->eof = 1; + } ++out: + return status; + } + +@@ -740,19 +759,6 @@ int nfs_do_filldir(nfs_readdir_descripto + struct nfs_cache_array *array = NULL; + struct nfs_open_dir_context *ctx = file->private_data; + +- if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) { +- if (printk_ratelimit()) { +- pr_notice("NFS: directory %s/%s contains a readdir loop. " +- "Please contact your server vendor. " +- "Offending cookie: %llu\n", +- file->f_dentry->d_parent->d_name.name, +- file->f_dentry->d_name.name, +- *desc->dir_cookie); +- } +- res = -ELOOP; +- goto out; +- } +- + array = nfs_readdir_get_array(desc->page); + if (IS_ERR(array)) { + res = PTR_ERR(array); +@@ -774,6 +780,8 @@ int nfs_do_filldir(nfs_readdir_descripto + *desc->dir_cookie = array->array[i+1].cookie; + else + *desc->dir_cookie = array->last_cookie; ++ if (ctx->duped != 0) ++ ctx->duped = 1; + } + if (array->eof_index >= 0) + desc->eof = 1; +@@ -805,6 +813,7 @@ int uncached_readdir(nfs_readdir_descrip + struct page *page = NULL; + int status; + struct inode *inode = desc->file->f_path.dentry->d_inode; ++ struct nfs_open_dir_context *ctx = desc->file->private_data; + + dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n", + (unsigned long long)*desc->dir_cookie); +@@ -818,6 +827,7 @@ int uncached_readdir(nfs_readdir_descrip + desc->page_index = 0; + desc->last_cookie = *desc->dir_cookie; + desc->page = page; ++ ctx->duped = 0; + + status = nfs_readdir_xdr_to_array(desc, page, inode); + if (status < 0) +--- a/include/linux/nfs_fs.h ++++ b/include/linux/nfs_fs.h +@@ -99,9 +99,10 @@ struct nfs_open_context { + + struct nfs_open_dir_context { + struct rpc_cred *cred; ++ unsigned long attr_gencount; + __u64 dir_cookie; + __u64 dup_cookie; +- int duped; ++ signed char duped; + }; + + /* diff --git a/queue-3.0/nfsd-don-t-break-lease-on-claim_delegate_cur.patch b/queue-3.0/nfsd-don-t-break-lease-on-claim_delegate_cur.patch new file mode 100644 index 0000000000..2c7cb41f51 --- /dev/null +++ b/queue-3.0/nfsd-don-t-break-lease-on-claim_delegate_cur.patch @@ -0,0 +1,68 @@ +From 0c12eaffdf09466f36a9ffe970dda8f4aeb6efc0 Mon Sep 17 00:00:00 2001 +From: Casey Bodley <cbodley@citi.umich.edu> +Date: Sat, 23 Jul 2011 14:58:10 -0400 +Subject: nfsd: don't break lease on CLAIM_DELEGATE_CUR + +From: Casey Bodley <cbodley@citi.umich.edu> + +commit 0c12eaffdf09466f36a9ffe970dda8f4aeb6efc0 upstream. + +CLAIM_DELEGATE_CUR is used in response to a broken lease; allowing it +to break the lease and return EAGAIN leaves the client unable to make +progress in returning the delegation + +nfs4_get_vfs_file() now takes struct nfsd4_open for access to the +claim type, and calls nfsd_open() with NFSD_MAY_NOT_BREAK_LEASE when +claim type is CLAIM_DELEGATE_CUR + +Signed-off-by: Casey Bodley <cbodley@citi.umich.edu> +Signed-off-by: J. Bruce Fields <bfields@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/nfsd/nfs4state.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2556,12 +2556,18 @@ static inline int nfs4_access_to_access( + return flags; + } + +-static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file +-*fp, struct svc_fh *cur_fh, u32 nfs4_access) ++static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, ++ struct svc_fh *cur_fh, struct nfsd4_open *open) + { + __be32 status; +- int oflag = nfs4_access_to_omode(nfs4_access); +- int access = nfs4_access_to_access(nfs4_access); ++ int oflag = nfs4_access_to_omode(open->op_share_access); ++ int access = nfs4_access_to_access(open->op_share_access); ++ ++ /* CLAIM_DELEGATE_CUR is used in response to a broken lease; ++ * allowing it to break the lease and return EAGAIN leaves the ++ * client unable to make progress in returning the delegation */ ++ if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) ++ access |= NFSD_MAY_NOT_BREAK_LEASE; + + if (!fp->fi_fds[oflag]) { + status = nfsd_open(rqstp, cur_fh, S_IFREG, access, +@@ -2586,7 +2592,7 @@ nfs4_new_open(struct svc_rqst *rqstp, st + if (stp == NULL) + return nfserr_resource; + +- status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access); ++ status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); + if (status) { + kmem_cache_free(stateid_slab, stp); + return status; +@@ -2619,7 +2625,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp + + new_access = !test_bit(op_share_access, &stp->st_access_bmap); + if (new_access) { +- status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access); ++ status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); + if (status) + return status; + } diff --git a/queue-3.0/nfsd4-fix-file-leak-on-open_downgrade.patch b/queue-3.0/nfsd4-fix-file-leak-on-open_downgrade.patch new file mode 100644 index 0000000000..cd3dbc3a46 --- /dev/null +++ b/queue-3.0/nfsd4-fix-file-leak-on-open_downgrade.patch @@ -0,0 +1,103 @@ +From f197c27196a5e7631b89e2e92daa096fcf7c302c Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" <bfields@redhat.com> +Date: Wed, 29 Jun 2011 08:23:50 -0400 +Subject: nfsd4: fix file leak on open_downgrade + +From: "J. Bruce Fields" <bfields@redhat.com> + +commit f197c27196a5e7631b89e2e92daa096fcf7c302c upstream. + +Stateid's hold a read reference for a read open, a write reference for a +write open, and an additional one of each for each read+write open. The +latter wasn't getting put on a downgrade, so something like: + + open RW + open R + downgrade to R + +was resulting in a file leak. + +Also fix an imbalance in an error path. + +Regression from 7d94784293096c0a46897acdb83be5abd9278ece "nfsd4: fix +downgrade/lock logic". + +Signed-off-by: J. Bruce Fields <bfields@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/nfsd/nfs4state.c | 31 ++++++++----------------------- + 1 file changed, 8 insertions(+), 23 deletions(-) + +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2332,15 +2332,6 @@ out: + return ret; + } + +-static inline void +-nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) +-{ +- if (share_access & NFS4_SHARE_ACCESS_WRITE) +- nfs4_file_put_access(fp, O_WRONLY); +- if (share_access & NFS4_SHARE_ACCESS_READ) +- nfs4_file_put_access(fp, O_RDONLY); +-} +- + static void nfsd_break_one_deleg(struct nfs4_delegation *dp) + { + /* We're assuming the state code never drops its reference +@@ -2627,7 +2618,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp + status = nfsd4_truncate(rqstp, cur_fh, open); + if (status) { + if (new_access) { +- int oflag = nfs4_access_to_omode(new_access); ++ int oflag = nfs4_access_to_omode(op_share_access); + nfs4_file_put_access(fp, oflag); + } + return status; +@@ -3385,18 +3376,15 @@ out: + return status; + } + +- +-/* +- * unset all bits in union bitmap (bmap) that +- * do not exist in share (from successful OPEN_DOWNGRADE) +- */ +-static void +-reset_union_bmap_access(unsigned long access, unsigned long *bmap) ++static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access) + { + int i; ++ + for (i = 1; i < 4; i++) { +- if ((i & access) != i) +- __clear_bit(i, bmap); ++ if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) { ++ nfs4_file_put_access(stp->st_file, i); ++ __clear_bit(i, &stp->st_access_bmap); ++ } + } + } + +@@ -3417,7 +3405,6 @@ nfsd4_open_downgrade(struct svc_rqst *rq + { + __be32 status; + struct nfs4_stateid *stp; +- unsigned int share_access; + + dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", + (int)cstate->current_fh.fh_dentry->d_name.len, +@@ -3446,10 +3433,8 @@ nfsd4_open_downgrade(struct svc_rqst *rq + stp->st_deny_bmap, od->od_share_deny); + goto out; + } +- set_access(&share_access, stp->st_access_bmap); +- nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access); ++ nfs4_file_downgrade(stp, od->od_share_access); + +- reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); + reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); + + update_stateid(&stp->st_stateid); diff --git a/queue-3.0/nfsd4-remember-to-put-rw-access-on-stateid-destruction.patch b/queue-3.0/nfsd4-remember-to-put-rw-access-on-stateid-destruction.patch new file mode 100644 index 0000000000..dff1d6a5a4 --- /dev/null +++ b/queue-3.0/nfsd4-remember-to-put-rw-access-on-stateid-destruction.patch @@ -0,0 +1,62 @@ +From 499f3edc23ca0431f3a0a6736b3a40944c81bf3b Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" <bfields@redhat.com> +Date: Mon, 27 Jun 2011 16:57:12 -0400 +Subject: nfsd4: remember to put RW access on stateid destruction + +From: "J. Bruce Fields" <bfields@redhat.com> + +commit 499f3edc23ca0431f3a0a6736b3a40944c81bf3b upstream. + +Without this, for example, + + open read + open read+write + close + +will result in a struct file leak. + +Regression from 7d94784293096c0a46897acdb83be5abd9278ece "nfsd4: fix +downgrade/lock logic". + +Signed-off-by: J. Bruce Fields <bfields@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/nfsd/nfs4state.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -381,14 +381,6 @@ static int nfs4_access_to_omode(u32 acce + BUG(); + } + +-static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) +-{ +- unsigned int access; +- +- set_access(&access, stp->st_access_bmap); +- return nfs4_access_to_omode(access); +-} +- + static void unhash_generic_stateid(struct nfs4_stateid *stp) + { + list_del(&stp->st_hash); +@@ -398,11 +390,14 @@ static void unhash_generic_stateid(struc + + static void free_generic_stateid(struct nfs4_stateid *stp) + { +- int oflag; ++ int i; + + if (stp->st_access_bmap) { +- oflag = nfs4_access_bmap_to_omode(stp); +- nfs4_file_put_access(stp->st_file, oflag); ++ for (i = 1; i < 4; i++) { ++ if (test_bit(i, &stp->st_access_bmap)) ++ nfs4_file_put_access(stp->st_file, ++ nfs4_access_to_omode(i)); ++ } + } + put_nfs4_file(stp->st_file); + kmem_cache_free(stateid_slab, stp); diff --git a/queue-3.0/nfsv4-don-t-use-the-delegation-inode-in.patch b/queue-3.0/nfsv4-don-t-use-the-delegation-inode-in.patch new file mode 100644 index 0000000000..6c8a3338d3 --- /dev/null +++ b/queue-3.0/nfsv4-don-t-use-the-delegation-inode-in.patch @@ -0,0 +1,78 @@ +From ed1e6211a0a134ff23592c6f057af982ad5dab52 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust <Trond.Myklebust@netapp.com> +Date: Mon, 25 Jul 2011 15:37:29 -0400 +Subject: NFSv4: Don't use the delegation->inode in + nfs_mark_return_delegation() + +From: Trond Myklebust <Trond.Myklebust@netapp.com> + +commit ed1e6211a0a134ff23592c6f057af982ad5dab52 upstream. + +nfs_mark_return_delegation() is usually called without any locking, and +so it is not safe to dereference delegation->inode. Since the inode is +only used to discover the nfs_client anyway, it makes more sense to +have the callers pass a valid pointer to the nfs_server as a parameter. + +Reported-by: Ian Kent <raven@themaw.net> +Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/nfs/delegation.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/fs/nfs/delegation.c ++++ b/fs/nfs/delegation.c +@@ -398,12 +398,11 @@ int nfs_inode_return_delegation(struct i + return err; + } + +-static void nfs_mark_return_delegation(struct nfs_delegation *delegation) ++static void nfs_mark_return_delegation(struct nfs_server *server, ++ struct nfs_delegation *delegation) + { +- struct nfs_client *clp = NFS_SERVER(delegation->inode)->nfs_client; +- + set_bit(NFS_DELEGATION_RETURN, &delegation->flags); +- set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); ++ set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); + } + + /** +@@ -441,7 +440,7 @@ static void nfs_mark_return_all_delegati + if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE)) + continue; + if (delegation->type & flags) +- nfs_mark_return_delegation(delegation); ++ nfs_mark_return_delegation(server, delegation); + } + } + +@@ -508,7 +507,7 @@ static void nfs_mark_return_unreferenced + list_for_each_entry_rcu(delegation, &server->delegations, super_list) { + if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) + continue; +- nfs_mark_return_delegation(delegation); ++ nfs_mark_return_delegation(server, delegation); + } + } + +@@ -539,7 +538,8 @@ void nfs_expire_unreferenced_delegations + int nfs_async_inode_return_delegation(struct inode *inode, + const nfs4_stateid *stateid) + { +- struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; ++ struct nfs_server *server = NFS_SERVER(inode); ++ struct nfs_client *clp = server->nfs_client; + struct nfs_delegation *delegation; + + rcu_read_lock(); +@@ -549,7 +549,7 @@ int nfs_async_inode_return_delegation(st + rcu_read_unlock(); + return -ENOENT; + } +- nfs_mark_return_delegation(delegation); ++ nfs_mark_return_delegation(server, delegation); + rcu_read_unlock(); + + nfs_delegation_run_state_manager(clp); diff --git a/queue-3.0/proc-fix-a-race-in-do_io_accounting.patch b/queue-3.0/proc-fix-a-race-in-do_io_accounting.patch new file mode 100644 index 0000000000..5e159365ae --- /dev/null +++ b/queue-3.0/proc-fix-a-race-in-do_io_accounting.patch @@ -0,0 +1,77 @@ +From 293eb1e7772b25a93647c798c7b89bf26c2da2e0 Mon Sep 17 00:00:00 2001 +From: Vasiliy Kulikov <segoon@openwall.com> +Date: Tue, 26 Jul 2011 16:08:38 -0700 +Subject: proc: fix a race in do_io_accounting() + +From: Vasiliy Kulikov <segoon@openwall.com> + +commit 293eb1e7772b25a93647c798c7b89bf26c2da2e0 upstream. + +If an inode's mode permits opening /proc/PID/io and the resulting file +descriptor is kept across execve() of a setuid or similar binary, the +ptrace_may_access() check tries to prevent using this fd against the +task with escalated privileges. + +Unfortunately, there is a race in the check against execve(). If +execve() is processed after the ptrace check, but before the actual io +information gathering, io statistics will be gathered from the +privileged process. At least in theory this might lead to gathering +sensible information (like ssh/ftp password length) that wouldn't be +available otherwise. + +Holding task->signal->cred_guard_mutex while gathering the io +information should protect against the race. + +The order of locking is similar to the one inside of ptrace_attach(): +first goes cred_guard_mutex, then lock_task_sighand(). + +Signed-off-by: Vasiliy Kulikov <segoon@openwall.com> +Cc: Al Viro <viro@zeniv.linux.org.uk> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/proc/base.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -2707,9 +2707,16 @@ static int do_io_accounting(struct task_ + { + struct task_io_accounting acct = task->ioac; + unsigned long flags; ++ int result; + +- if (!ptrace_may_access(task, PTRACE_MODE_READ)) +- return -EACCES; ++ result = mutex_lock_killable(&task->signal->cred_guard_mutex); ++ if (result) ++ return result; ++ ++ if (!ptrace_may_access(task, PTRACE_MODE_READ)) { ++ result = -EACCES; ++ goto out_unlock; ++ } + + if (whole && lock_task_sighand(task, &flags)) { + struct task_struct *t = task; +@@ -2720,7 +2727,7 @@ static int do_io_accounting(struct task_ + + unlock_task_sighand(task, &flags); + } +- return sprintf(buffer, ++ result = sprintf(buffer, + "rchar: %llu\n" + "wchar: %llu\n" + "syscr: %llu\n" +@@ -2735,6 +2742,9 @@ static int do_io_accounting(struct task_ + (unsigned long long)acct.read_bytes, + (unsigned long long)acct.write_bytes, + (unsigned long long)acct.cancelled_write_bytes); ++out_unlock: ++ mutex_unlock(&task->signal->cred_guard_mutex); ++ return result; + } + + static int proc_tid_io_accounting(struct task_struct *task, char *buffer) diff --git a/queue-3.0/series b/queue-3.0/series index f88e3b354c..d115d5b66d 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -70,3 +70,15 @@ xtensa-prevent-arbitrary-read-in-ptrace.patch ext4-fix-i_blocks-quota-accounting-when-extent-insertion-fails.patch ext4-free-allocated-and-pre-allocated-blocks-when.patch ext3-fix-oops-in-ext3_try_to_allocate_with_rsv.patch +ecryptfs-make-inode-bdi-consistent-with-superblock-bdi.patch +ecryptfs-unlock-keys-needed-by-ecryptfsd.patch +nfsd-don-t-break-lease-on-claim_delegate_cur.patch +nfsd4-remember-to-put-rw-access-on-stateid-destruction.patch +nfsd4-fix-file-leak-on-open_downgrade.patch +svcrpc-fix-list-corrupting-race-on-nfsd-shutdown.patch +nfsv4-don-t-use-the-delegation-inode-in.patch +nfs-fix-spurious-readdir-cookie-loop-messages.patch +proc-fix-a-race-in-do_io_accounting.patch +n_gsm-fix-the-wrong-fcs-handling.patch +ehci-only-power-off-port-if-over-current-is-active.patch +ehci-fix-direction-handling-for-interrupt-data-toggles.patch diff --git a/queue-3.0/svcrpc-fix-list-corrupting-race-on-nfsd-shutdown.patch b/queue-3.0/svcrpc-fix-list-corrupting-race-on-nfsd-shutdown.patch new file mode 100644 index 0000000000..07535049a1 --- /dev/null +++ b/queue-3.0/svcrpc-fix-list-corrupting-race-on-nfsd-shutdown.patch @@ -0,0 +1,54 @@ +From ebc63e531cc6a457595dd110b07ac530eae788c3 Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" <bfields@redhat.com> +Date: Wed, 29 Jun 2011 16:49:04 -0400 +Subject: svcrpc: fix list-corrupting race on nfsd shutdown + +From: "J. Bruce Fields" <bfields@redhat.com> + +commit ebc63e531cc6a457595dd110b07ac530eae788c3 upstream. + +After commit 3262c816a3d7fb1eaabce633caa317887ed549ae "[PATCH] knfsd: +split svc_serv into pools", svc_delete_xprt (then svc_delete_socket) no +longer removed its xpt_ready (then sk_ready) field from whatever list it +was on, noting that there was no point since the whole list was about to +be destroyed anyway. + +That was mostly true, but forgot that a few svc_xprt_enqueue()'s might +still be hanging around playing with the about-to-be-destroyed list, and +could get themselves into trouble writing to freed memory if we left +this xprt on the list after freeing it. + +(This is actually functionally identical to a patch made first by Ben +Greear, but with more comments.) + +Cc: gnb@fmeh.org +Reported-by: Ben Greear <greearb@candelatech.com> +Tested-by: Ben Greear <greearb@candelatech.com> +Signed-off-by: J. Bruce Fields <bfields@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + net/sunrpc/svc_xprt.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -902,12 +902,13 @@ void svc_delete_xprt(struct svc_xprt *xp + if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags)) + list_del_init(&xprt->xpt_list); + /* +- * We used to delete the transport from whichever list +- * it's sk_xprt.xpt_ready node was on, but we don't actually +- * need to. This is because the only time we're called +- * while still attached to a queue, the queue itself +- * is about to be destroyed (in svc_destroy). ++ * The only time we're called while xpt_ready is still on a list ++ * is while the list itself is about to be destroyed (in ++ * svc_destroy). BUT svc_xprt_enqueue could still be attempting ++ * to add new entries to the sp_sockets list, so we can't leave ++ * a freed xprt on it. + */ ++ list_del_init(&xprt->xpt_ready); + if (test_bit(XPT_TEMP, &xprt->xpt_flags)) + serv->sv_tmpcnt--; + spin_unlock_bh(&serv->sv_lock); |