aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-01-07 11:36:45 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-01-07 11:36:45 -0500
commit4c9014f2ca7e5ecf8806e838be0f07aa1810c985 (patch)
treedd33fdebedf1ce6497737113e183f2a5d8bbca63
parent5ce2955e04a80da7287dc12f32da7f870039bf8f (diff)
parentecf0eb9edbb607d74f74b73c14af8b43f3729528 (diff)
Merge tag 'nfs-for-3.8-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust: - Fix a permissions problem when opening NFSv4 files that only have the exec bit set. - Fix a couple of typos in pNFS (inverted logic), and the mount parsing (missing pointer dereference). - Work around a series of deadlock issues due to workqueues using struct work_struct pointer address comparisons in the re-entrancy tests. Ensure that we don't free struct work_struct prematurely if our work function involves waiting for completion of other work items (e.g. by calling rpc_shutdown_client). - Revert the part of commit 168e4b3 that is causing unnecessary warnings to be issued in the nfsd callback code. * tag 'nfs-for-3.8-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: nfs: avoid dereferencing null pointer in initiate_bulk_draining SUNRPC: Partial revert of commit 168e4b39d1afb79a7e3ea6c3bb246b4c82c6bdb9 NFS: Ensure that we free the rpc_task after read and write cleanups are done SUNRPC: Ensure that we free the rpc_task after cleanups are done nfs: fix null checking in nfs_get_option_str() pnfs: Increase the refcount when LAYOUTGET fails the first time NFS: Fix access to suid/sgid executables
-rw-r--r--fs/nfs/callback_proc.c2
-rw-r--r--fs/nfs/dir.c16
-rw-r--r--fs/nfs/nfs4proc.c18
-rw-r--r--fs/nfs/pnfs.c2
-rw-r--r--fs/nfs/read.c10
-rw-r--r--fs/nfs/super.c2
-rw-r--r--fs/nfs/write.c10
-rw-r--r--net/sunrpc/clnt.c5
-rw-r--r--net/sunrpc/sched.c27
9 files changed, 61 insertions, 31 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index c89b26bc9759..264d1aa935f2 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -206,7 +206,7 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
206 206
207 list_for_each_entry(lo, &server->layouts, plh_layouts) { 207 list_for_each_entry(lo, &server->layouts, plh_layouts) {
208 ino = igrab(lo->plh_inode); 208 ino = igrab(lo->plh_inode);
209 if (ino) 209 if (!ino)
210 continue; 210 continue;
211 spin_lock(&ino->i_lock); 211 spin_lock(&ino->i_lock);
212 /* Is this layout in the process of being freed? */ 212 /* Is this layout in the process of being freed? */
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 32e6c53520e2..1b2d7eb93796 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2153,12 +2153,16 @@ static int nfs_open_permission_mask(int openflags)
2153{ 2153{
2154 int mask = 0; 2154 int mask = 0;
2155 2155
2156 if ((openflags & O_ACCMODE) != O_WRONLY) 2156 if (openflags & __FMODE_EXEC) {
2157 mask |= MAY_READ; 2157 /* ONLY check exec rights */
2158 if ((openflags & O_ACCMODE) != O_RDONLY) 2158 mask = MAY_EXEC;
2159 mask |= MAY_WRITE; 2159 } else {
2160 if (openflags & __FMODE_EXEC) 2160 if ((openflags & O_ACCMODE) != O_WRONLY)
2161 mask |= MAY_EXEC; 2161 mask |= MAY_READ;
2162 if ((openflags & O_ACCMODE) != O_RDONLY)
2163 mask |= MAY_WRITE;
2164 }
2165
2162 return mask; 2166 return mask;
2163} 2167}
2164 2168
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5d864fb36578..cf747ef86650 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1626,7 +1626,8 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
1626 1626
1627static int nfs4_opendata_access(struct rpc_cred *cred, 1627static int nfs4_opendata_access(struct rpc_cred *cred,
1628 struct nfs4_opendata *opendata, 1628 struct nfs4_opendata *opendata,
1629 struct nfs4_state *state, fmode_t fmode) 1629 struct nfs4_state *state, fmode_t fmode,
1630 int openflags)
1630{ 1631{
1631 struct nfs_access_entry cache; 1632 struct nfs_access_entry cache;
1632 u32 mask; 1633 u32 mask;
@@ -1638,11 +1639,14 @@ static int nfs4_opendata_access(struct rpc_cred *cred,
1638 1639
1639 mask = 0; 1640 mask = 0;
1640 /* don't check MAY_WRITE - a newly created file may not have 1641 /* don't check MAY_WRITE - a newly created file may not have
1641 * write mode bits, but POSIX allows the creating process to write */ 1642 * write mode bits, but POSIX allows the creating process to write.
1642 if (fmode & FMODE_READ) 1643 * use openflags to check for exec, because fmode won't
1643 mask |= MAY_READ; 1644 * always have FMODE_EXEC set when file open for exec. */
1644 if (fmode & FMODE_EXEC) 1645 if (openflags & __FMODE_EXEC) {
1645 mask |= MAY_EXEC; 1646 /* ONLY check for exec rights */
1647 mask = MAY_EXEC;
1648 } else if (fmode & FMODE_READ)
1649 mask = MAY_READ;
1646 1650
1647 cache.cred = cred; 1651 cache.cred = cred;
1648 cache.jiffies = jiffies; 1652 cache.jiffies = jiffies;
@@ -1896,7 +1900,7 @@ static int _nfs4_do_open(struct inode *dir,
1896 if (server->caps & NFS_CAP_POSIX_LOCK) 1900 if (server->caps & NFS_CAP_POSIX_LOCK)
1897 set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); 1901 set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
1898 1902
1899 status = nfs4_opendata_access(cred, opendata, state, fmode); 1903 status = nfs4_opendata_access(cred, opendata, state, fmode, flags);
1900 if (status != 0) 1904 if (status != 0)
1901 goto err_opendata_put; 1905 goto err_opendata_put;
1902 1906
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index e7165d915362..d00260b08103 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -254,7 +254,7 @@ static void
254pnfs_layout_set_fail_bit(struct pnfs_layout_hdr *lo, int fail_bit) 254pnfs_layout_set_fail_bit(struct pnfs_layout_hdr *lo, int fail_bit)
255{ 255{
256 lo->plh_retry_timestamp = jiffies; 256 lo->plh_retry_timestamp = jiffies;
257 if (test_and_set_bit(fail_bit, &lo->plh_flags)) 257 if (!test_and_set_bit(fail_bit, &lo->plh_flags))
258 atomic_inc(&lo->plh_refcount); 258 atomic_inc(&lo->plh_refcount);
259} 259}
260 260
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index b6bdb18e892c..a5e5d9899d56 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -91,12 +91,16 @@ void nfs_readdata_release(struct nfs_read_data *rdata)
91 put_nfs_open_context(rdata->args.context); 91 put_nfs_open_context(rdata->args.context);
92 if (rdata->pages.pagevec != rdata->pages.page_array) 92 if (rdata->pages.pagevec != rdata->pages.page_array)
93 kfree(rdata->pages.pagevec); 93 kfree(rdata->pages.pagevec);
94 if (rdata != &read_header->rpc_data) 94 if (rdata == &read_header->rpc_data) {
95 kfree(rdata);
96 else
97 rdata->header = NULL; 95 rdata->header = NULL;
96 rdata = NULL;
97 }
98 if (atomic_dec_and_test(&hdr->refcnt)) 98 if (atomic_dec_and_test(&hdr->refcnt))
99 hdr->completion_ops->completion(hdr); 99 hdr->completion_ops->completion(hdr);
100 /* Note: we only free the rpc_task after callbacks are done.
101 * See the comment in rpc_free_task() for why
102 */
103 kfree(rdata);
100} 104}
101EXPORT_SYMBOL_GPL(nfs_readdata_release); 105EXPORT_SYMBOL_GPL(nfs_readdata_release);
102 106
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index c25cadf8f8c4..2e7e8c878e5d 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1152,7 +1152,7 @@ static int nfs_get_option_str(substring_t args[], char **option)
1152{ 1152{
1153 kfree(*option); 1153 kfree(*option);
1154 *option = match_strdup(args); 1154 *option = match_strdup(args);
1155 return !option; 1155 return !*option;
1156} 1156}
1157 1157
1158static int nfs_get_option_ul(substring_t args[], unsigned long *option) 1158static int nfs_get_option_ul(substring_t args[], unsigned long *option)
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index b673be31590e..c483cc50b82e 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -126,12 +126,16 @@ void nfs_writedata_release(struct nfs_write_data *wdata)
126 put_nfs_open_context(wdata->args.context); 126 put_nfs_open_context(wdata->args.context);
127 if (wdata->pages.pagevec != wdata->pages.page_array) 127 if (wdata->pages.pagevec != wdata->pages.page_array)
128 kfree(wdata->pages.pagevec); 128 kfree(wdata->pages.pagevec);
129 if (wdata != &write_header->rpc_data) 129 if (wdata == &write_header->rpc_data) {
130 kfree(wdata);
131 else
132 wdata->header = NULL; 130 wdata->header = NULL;
131 wdata = NULL;
132 }
133 if (atomic_dec_and_test(&hdr->refcnt)) 133 if (atomic_dec_and_test(&hdr->refcnt))
134 hdr->completion_ops->completion(hdr); 134 hdr->completion_ops->completion(hdr);
135 /* Note: we only free the rpc_task after callbacks are done.
136 * See the comment in rpc_free_task() for why
137 */
138 kfree(wdata);
135} 139}
136EXPORT_SYMBOL_GPL(nfs_writedata_release); 140EXPORT_SYMBOL_GPL(nfs_writedata_release);
137 141
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 822f020fa7f4..1915ffe598e3 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -610,11 +610,6 @@ EXPORT_SYMBOL_GPL(rpc_killall_tasks);
610 */ 610 */
611void rpc_shutdown_client(struct rpc_clnt *clnt) 611void rpc_shutdown_client(struct rpc_clnt *clnt)
612{ 612{
613 /*
614 * To avoid deadlock, never call rpc_shutdown_client from a
615 * workqueue context!
616 */
617 WARN_ON_ONCE(current->flags & PF_WQ_WORKER);
618 might_sleep(); 613 might_sleep();
619 614
620 dprintk_rcu("RPC: shutting down %s client for %s\n", 615 dprintk_rcu("RPC: shutting down %s client for %s\n",
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index d17a704aaf5f..b4133bd13915 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -934,16 +934,35 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data)
934 return task; 934 return task;
935} 935}
936 936
937/*
938 * rpc_free_task - release rpc task and perform cleanups
939 *
940 * Note that we free up the rpc_task _after_ rpc_release_calldata()
941 * in order to work around a workqueue dependency issue.
942 *
943 * Tejun Heo states:
944 * "Workqueue currently considers two work items to be the same if they're
945 * on the same address and won't execute them concurrently - ie. it
946 * makes a work item which is queued again while being executed wait
947 * for the previous execution to complete.
948 *
949 * If a work function frees the work item, and then waits for an event
950 * which should be performed by another work item and *that* work item
951 * recycles the freed work item, it can create a false dependency loop.
952 * There really is no reliable way to detect this short of verifying
953 * every memory free."
954 *
955 */
937static void rpc_free_task(struct rpc_task *task) 956static void rpc_free_task(struct rpc_task *task)
938{ 957{
939 const struct rpc_call_ops *tk_ops = task->tk_ops; 958 unsigned short tk_flags = task->tk_flags;
940 void *calldata = task->tk_calldata; 959
960 rpc_release_calldata(task->tk_ops, task->tk_calldata);
941 961
942 if (task->tk_flags & RPC_TASK_DYNAMIC) { 962 if (tk_flags & RPC_TASK_DYNAMIC) {
943 dprintk("RPC: %5u freeing task\n", task->tk_pid); 963 dprintk("RPC: %5u freeing task\n", task->tk_pid);
944 mempool_free(task, rpc_task_mempool); 964 mempool_free(task, rpc_task_mempool);
945 } 965 }
946 rpc_release_calldata(tk_ops, calldata);
947} 966}
948 967
949static void rpc_async_release(struct work_struct *work) 968static void rpc_async_release(struct work_struct *work)