diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Kconfig | 4 | ||||
-rw-r--r-- | fs/dcache.c | 164 | ||||
-rw-r--r-- | fs/lockd/clntproc.c | 10 | ||||
-rw-r--r-- | fs/lockd/host.c | 51 | ||||
-rw-r--r-- | fs/lockd/mon.c | 41 | ||||
-rw-r--r-- | fs/nfs/Makefile | 6 | ||||
-rw-r--r-- | fs/nfs/callback.c | 31 | ||||
-rw-r--r-- | fs/nfs/callback.h | 7 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 13 | ||||
-rw-r--r-- | fs/nfs/client.c | 1448 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 35 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 10 | ||||
-rw-r--r-- | fs/nfs/dir.c | 338 | ||||
-rw-r--r-- | fs/nfs/file.c | 4 | ||||
-rw-r--r-- | fs/nfs/getroot.c | 311 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 45 | ||||
-rw-r--r-- | fs/nfs/inode.c | 46 | ||||
-rw-r--r-- | fs/nfs/internal.h | 105 | ||||
-rw-r--r-- | fs/nfs/mount_clnt.c | 30 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 34 | ||||
-rw-r--r-- | fs/nfs/nfs2xdr.c | 21 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 42 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 7 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 78 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 118 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 218 | ||||
-rw-r--r-- | fs/nfs/nfs4renewd.c | 20 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 174 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 50 | ||||
-rw-r--r-- | fs/nfs/proc.c | 41 | ||||
-rw-r--r-- | fs/nfs/read.c | 21 | ||||
-rw-r--r-- | fs/nfs/super.c | 1411 | ||||
-rw-r--r-- | fs/nfs/write.c | 11 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 66 |
34 files changed, 3326 insertions, 1685 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 530581628311..a27002668bd3 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1471,8 +1471,8 @@ config NFS_V4 | |||
1471 | If unsure, say N. | 1471 | If unsure, say N. |
1472 | 1472 | ||
1473 | config NFS_DIRECTIO | 1473 | config NFS_DIRECTIO |
1474 | bool "Allow direct I/O on NFS files (EXPERIMENTAL)" | 1474 | bool "Allow direct I/O on NFS files" |
1475 | depends on NFS_FS && EXPERIMENTAL | 1475 | depends on NFS_FS |
1476 | help | 1476 | help |
1477 | This option enables applications to perform uncached I/O on files | 1477 | This option enables applications to perform uncached I/O on files |
1478 | in NFS file systems using the O_DIRECT open() flag. When O_DIRECT | 1478 | in NFS file systems using the O_DIRECT open() flag. When O_DIRECT |
diff --git a/fs/dcache.c b/fs/dcache.c index 1b4a3a34ec57..17b392a2049e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -828,17 +828,19 @@ void d_instantiate(struct dentry *entry, struct inode * inode) | |||
828 | * (or otherwise set) by the caller to indicate that it is now | 828 | * (or otherwise set) by the caller to indicate that it is now |
829 | * in use by the dcache. | 829 | * in use by the dcache. |
830 | */ | 830 | */ |
831 | struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | 831 | static struct dentry *__d_instantiate_unique(struct dentry *entry, |
832 | struct inode *inode) | ||
832 | { | 833 | { |
833 | struct dentry *alias; | 834 | struct dentry *alias; |
834 | int len = entry->d_name.len; | 835 | int len = entry->d_name.len; |
835 | const char *name = entry->d_name.name; | 836 | const char *name = entry->d_name.name; |
836 | unsigned int hash = entry->d_name.hash; | 837 | unsigned int hash = entry->d_name.hash; |
837 | 838 | ||
838 | BUG_ON(!list_empty(&entry->d_alias)); | 839 | if (!inode) { |
839 | spin_lock(&dcache_lock); | 840 | entry->d_inode = NULL; |
840 | if (!inode) | 841 | return NULL; |
841 | goto do_negative; | 842 | } |
843 | |||
842 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { | 844 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { |
843 | struct qstr *qstr = &alias->d_name; | 845 | struct qstr *qstr = &alias->d_name; |
844 | 846 | ||
@@ -851,19 +853,35 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | |||
851 | if (memcmp(qstr->name, name, len)) | 853 | if (memcmp(qstr->name, name, len)) |
852 | continue; | 854 | continue; |
853 | dget_locked(alias); | 855 | dget_locked(alias); |
854 | spin_unlock(&dcache_lock); | ||
855 | BUG_ON(!d_unhashed(alias)); | ||
856 | iput(inode); | ||
857 | return alias; | 856 | return alias; |
858 | } | 857 | } |
858 | |||
859 | list_add(&entry->d_alias, &inode->i_dentry); | 859 | list_add(&entry->d_alias, &inode->i_dentry); |
860 | do_negative: | ||
861 | entry->d_inode = inode; | 860 | entry->d_inode = inode; |
862 | fsnotify_d_instantiate(entry, inode); | 861 | fsnotify_d_instantiate(entry, inode); |
863 | spin_unlock(&dcache_lock); | ||
864 | security_d_instantiate(entry, inode); | ||
865 | return NULL; | 862 | return NULL; |
866 | } | 863 | } |
864 | |||
865 | struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | ||
866 | { | ||
867 | struct dentry *result; | ||
868 | |||
869 | BUG_ON(!list_empty(&entry->d_alias)); | ||
870 | |||
871 | spin_lock(&dcache_lock); | ||
872 | result = __d_instantiate_unique(entry, inode); | ||
873 | spin_unlock(&dcache_lock); | ||
874 | |||
875 | if (!result) { | ||
876 | security_d_instantiate(entry, inode); | ||
877 | return NULL; | ||
878 | } | ||
879 | |||
880 | BUG_ON(!d_unhashed(result)); | ||
881 | iput(inode); | ||
882 | return result; | ||
883 | } | ||
884 | |||
867 | EXPORT_SYMBOL(d_instantiate_unique); | 885 | EXPORT_SYMBOL(d_instantiate_unique); |
868 | 886 | ||
869 | /** | 887 | /** |
@@ -1235,6 +1253,11 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list) | |||
1235 | hlist_add_head_rcu(&entry->d_hash, list); | 1253 | hlist_add_head_rcu(&entry->d_hash, list); |
1236 | } | 1254 | } |
1237 | 1255 | ||
1256 | static void _d_rehash(struct dentry * entry) | ||
1257 | { | ||
1258 | __d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash)); | ||
1259 | } | ||
1260 | |||
1238 | /** | 1261 | /** |
1239 | * d_rehash - add an entry back to the hash | 1262 | * d_rehash - add an entry back to the hash |
1240 | * @entry: dentry to add to the hash | 1263 | * @entry: dentry to add to the hash |
@@ -1244,11 +1267,9 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list) | |||
1244 | 1267 | ||
1245 | void d_rehash(struct dentry * entry) | 1268 | void d_rehash(struct dentry * entry) |
1246 | { | 1269 | { |
1247 | struct hlist_head *list = d_hash(entry->d_parent, entry->d_name.hash); | ||
1248 | |||
1249 | spin_lock(&dcache_lock); | 1270 | spin_lock(&dcache_lock); |
1250 | spin_lock(&entry->d_lock); | 1271 | spin_lock(&entry->d_lock); |
1251 | __d_rehash(entry, list); | 1272 | _d_rehash(entry); |
1252 | spin_unlock(&entry->d_lock); | 1273 | spin_unlock(&entry->d_lock); |
1253 | spin_unlock(&dcache_lock); | 1274 | spin_unlock(&dcache_lock); |
1254 | } | 1275 | } |
@@ -1386,6 +1407,120 @@ already_unhashed: | |||
1386 | spin_unlock(&dcache_lock); | 1407 | spin_unlock(&dcache_lock); |
1387 | } | 1408 | } |
1388 | 1409 | ||
1410 | /* | ||
1411 | * Prepare an anonymous dentry for life in the superblock's dentry tree as a | ||
1412 | * named dentry in place of the dentry to be replaced. | ||
1413 | */ | ||
1414 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | ||
1415 | { | ||
1416 | struct dentry *dparent, *aparent; | ||
1417 | |||
1418 | switch_names(dentry, anon); | ||
1419 | do_switch(dentry->d_name.len, anon->d_name.len); | ||
1420 | do_switch(dentry->d_name.hash, anon->d_name.hash); | ||
1421 | |||
1422 | dparent = dentry->d_parent; | ||
1423 | aparent = anon->d_parent; | ||
1424 | |||
1425 | dentry->d_parent = (aparent == anon) ? dentry : aparent; | ||
1426 | list_del(&dentry->d_u.d_child); | ||
1427 | if (!IS_ROOT(dentry)) | ||
1428 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); | ||
1429 | else | ||
1430 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
1431 | |||
1432 | anon->d_parent = (dparent == dentry) ? anon : dparent; | ||
1433 | list_del(&anon->d_u.d_child); | ||
1434 | if (!IS_ROOT(anon)) | ||
1435 | list_add(&anon->d_u.d_child, &anon->d_parent->d_subdirs); | ||
1436 | else | ||
1437 | INIT_LIST_HEAD(&anon->d_u.d_child); | ||
1438 | |||
1439 | anon->d_flags &= ~DCACHE_DISCONNECTED; | ||
1440 | } | ||
1441 | |||
1442 | /** | ||
1443 | * d_materialise_unique - introduce an inode into the tree | ||
1444 | * @dentry: candidate dentry | ||
1445 | * @inode: inode to bind to the dentry, to which aliases may be attached | ||
1446 | * | ||
1447 | * Introduces an dentry into the tree, substituting an extant disconnected | ||
1448 | * root directory alias in its place if there is one | ||
1449 | */ | ||
1450 | struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | ||
1451 | { | ||
1452 | struct dentry *alias, *actual; | ||
1453 | |||
1454 | BUG_ON(!d_unhashed(dentry)); | ||
1455 | |||
1456 | spin_lock(&dcache_lock); | ||
1457 | |||
1458 | if (!inode) { | ||
1459 | actual = dentry; | ||
1460 | dentry->d_inode = NULL; | ||
1461 | goto found_lock; | ||
1462 | } | ||
1463 | |||
1464 | /* See if a disconnected directory already exists as an anonymous root | ||
1465 | * that we should splice into the tree instead */ | ||
1466 | if (S_ISDIR(inode->i_mode) && (alias = __d_find_alias(inode, 1))) { | ||
1467 | spin_lock(&alias->d_lock); | ||
1468 | |||
1469 | /* Is this a mountpoint that we could splice into our tree? */ | ||
1470 | if (IS_ROOT(alias)) | ||
1471 | goto connect_mountpoint; | ||
1472 | |||
1473 | if (alias->d_name.len == dentry->d_name.len && | ||
1474 | alias->d_parent == dentry->d_parent && | ||
1475 | memcmp(alias->d_name.name, | ||
1476 | dentry->d_name.name, | ||
1477 | dentry->d_name.len) == 0) | ||
1478 | goto replace_with_alias; | ||
1479 | |||
1480 | spin_unlock(&alias->d_lock); | ||
1481 | |||
1482 | /* Doh! Seem to be aliasing directories for some reason... */ | ||
1483 | dput(alias); | ||
1484 | } | ||
1485 | |||
1486 | /* Add a unique reference */ | ||
1487 | actual = __d_instantiate_unique(dentry, inode); | ||
1488 | if (!actual) | ||
1489 | actual = dentry; | ||
1490 | else if (unlikely(!d_unhashed(actual))) | ||
1491 | goto shouldnt_be_hashed; | ||
1492 | |||
1493 | found_lock: | ||
1494 | spin_lock(&actual->d_lock); | ||
1495 | found: | ||
1496 | _d_rehash(actual); | ||
1497 | spin_unlock(&actual->d_lock); | ||
1498 | spin_unlock(&dcache_lock); | ||
1499 | |||
1500 | if (actual == dentry) { | ||
1501 | security_d_instantiate(dentry, inode); | ||
1502 | return NULL; | ||
1503 | } | ||
1504 | |||
1505 | iput(inode); | ||
1506 | return actual; | ||
1507 | |||
1508 | /* Convert the anonymous/root alias into an ordinary dentry */ | ||
1509 | connect_mountpoint: | ||
1510 | __d_materialise_dentry(dentry, alias); | ||
1511 | |||
1512 | /* Replace the candidate dentry with the alias in the tree */ | ||
1513 | replace_with_alias: | ||
1514 | __d_drop(alias); | ||
1515 | actual = alias; | ||
1516 | goto found; | ||
1517 | |||
1518 | shouldnt_be_hashed: | ||
1519 | spin_unlock(&dcache_lock); | ||
1520 | BUG(); | ||
1521 | goto shouldnt_be_hashed; | ||
1522 | } | ||
1523 | |||
1389 | /** | 1524 | /** |
1390 | * d_path - return the path of a dentry | 1525 | * d_path - return the path of a dentry |
1391 | * @dentry: dentry to report | 1526 | * @dentry: dentry to report |
@@ -1784,6 +1919,7 @@ EXPORT_SYMBOL(d_instantiate); | |||
1784 | EXPORT_SYMBOL(d_invalidate); | 1919 | EXPORT_SYMBOL(d_invalidate); |
1785 | EXPORT_SYMBOL(d_lookup); | 1920 | EXPORT_SYMBOL(d_lookup); |
1786 | EXPORT_SYMBOL(d_move); | 1921 | EXPORT_SYMBOL(d_move); |
1922 | EXPORT_SYMBOL_GPL(d_materialise_unique); | ||
1787 | EXPORT_SYMBOL(d_path); | 1923 | EXPORT_SYMBOL(d_path); |
1788 | EXPORT_SYMBOL(d_prune_aliases); | 1924 | EXPORT_SYMBOL(d_prune_aliases); |
1789 | EXPORT_SYMBOL(d_rehash); | 1925 | EXPORT_SYMBOL(d_rehash); |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 89ba0df14c22..50dbb67ae0c4 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -151,11 +151,13 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) | |||
151 | int | 151 | int |
152 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | 152 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) |
153 | { | 153 | { |
154 | struct rpc_clnt *client = NFS_CLIENT(inode); | ||
155 | struct sockaddr_in addr; | ||
154 | struct nlm_host *host; | 156 | struct nlm_host *host; |
155 | struct nlm_rqst *call; | 157 | struct nlm_rqst *call; |
156 | sigset_t oldset; | 158 | sigset_t oldset; |
157 | unsigned long flags; | 159 | unsigned long flags; |
158 | int status, proto, vers; | 160 | int status, vers; |
159 | 161 | ||
160 | vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; | 162 | vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; |
161 | if (NFS_PROTO(inode)->version > 3) { | 163 | if (NFS_PROTO(inode)->version > 3) { |
@@ -163,10 +165,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
163 | return -ENOLCK; | 165 | return -ENOLCK; |
164 | } | 166 | } |
165 | 167 | ||
166 | /* Retrieve transport protocol from NFS client */ | 168 | rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr)); |
167 | proto = NFS_CLIENT(inode)->cl_xprt->prot; | 169 | host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers); |
168 | |||
169 | host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers); | ||
170 | if (host == NULL) | 170 | if (host == NULL) |
171 | return -ENOLCK; | 171 | return -ENOLCK; |
172 | 172 | ||
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 38b0e8a1aec0..703fb038c813 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #define NLM_HOST_REBIND (60 * HZ) | 26 | #define NLM_HOST_REBIND (60 * HZ) |
27 | #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) | 27 | #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) |
28 | #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) | 28 | #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) |
29 | #define NLM_HOST_ADDR(sv) (&(sv)->s_nlmclnt->cl_xprt->addr) | ||
30 | 29 | ||
31 | static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH]; | 30 | static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH]; |
32 | static unsigned long next_gc; | 31 | static unsigned long next_gc; |
@@ -167,7 +166,6 @@ struct rpc_clnt * | |||
167 | nlm_bind_host(struct nlm_host *host) | 166 | nlm_bind_host(struct nlm_host *host) |
168 | { | 167 | { |
169 | struct rpc_clnt *clnt; | 168 | struct rpc_clnt *clnt; |
170 | struct rpc_xprt *xprt; | ||
171 | 169 | ||
172 | dprintk("lockd: nlm_bind_host(%08x)\n", | 170 | dprintk("lockd: nlm_bind_host(%08x)\n", |
173 | (unsigned)ntohl(host->h_addr.sin_addr.s_addr)); | 171 | (unsigned)ntohl(host->h_addr.sin_addr.s_addr)); |
@@ -179,7 +177,6 @@ nlm_bind_host(struct nlm_host *host) | |||
179 | * RPC rebind is required | 177 | * RPC rebind is required |
180 | */ | 178 | */ |
181 | if ((clnt = host->h_rpcclnt) != NULL) { | 179 | if ((clnt = host->h_rpcclnt) != NULL) { |
182 | xprt = clnt->cl_xprt; | ||
183 | if (time_after_eq(jiffies, host->h_nextrebind)) { | 180 | if (time_after_eq(jiffies, host->h_nextrebind)) { |
184 | rpc_force_rebind(clnt); | 181 | rpc_force_rebind(clnt); |
185 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; | 182 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; |
@@ -187,31 +184,37 @@ nlm_bind_host(struct nlm_host *host) | |||
187 | host->h_nextrebind - jiffies); | 184 | host->h_nextrebind - jiffies); |
188 | } | 185 | } |
189 | } else { | 186 | } else { |
190 | xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL); | 187 | unsigned long increment = nlmsvc_timeout * HZ; |
191 | if (IS_ERR(xprt)) | 188 | struct rpc_timeout timeparms = { |
192 | goto forgetit; | 189 | .to_initval = increment, |
193 | 190 | .to_increment = increment, | |
194 | xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); | 191 | .to_maxval = increment * 6UL, |
195 | xprt->resvport = 1; /* NLM requires a reserved port */ | 192 | .to_retries = 5U, |
196 | 193 | }; | |
197 | /* Existing NLM servers accept AUTH_UNIX only */ | 194 | struct rpc_create_args args = { |
198 | clnt = rpc_new_client(xprt, host->h_name, &nlm_program, | 195 | .protocol = host->h_proto, |
199 | host->h_version, RPC_AUTH_UNIX); | 196 | .address = (struct sockaddr *)&host->h_addr, |
200 | if (IS_ERR(clnt)) | 197 | .addrsize = sizeof(host->h_addr), |
201 | goto forgetit; | 198 | .timeout = &timeparms, |
202 | clnt->cl_autobind = 1; /* turn on pmap queries */ | 199 | .servername = host->h_name, |
203 | clnt->cl_softrtry = 1; /* All queries are soft */ | 200 | .program = &nlm_program, |
204 | 201 | .version = host->h_version, | |
205 | host->h_rpcclnt = clnt; | 202 | .authflavor = RPC_AUTH_UNIX, |
203 | .flags = (RPC_CLNT_CREATE_HARDRTRY | | ||
204 | RPC_CLNT_CREATE_AUTOBIND), | ||
205 | }; | ||
206 | |||
207 | clnt = rpc_create(&args); | ||
208 | if (!IS_ERR(clnt)) | ||
209 | host->h_rpcclnt = clnt; | ||
210 | else { | ||
211 | printk("lockd: couldn't create RPC handle for %s\n", host->h_name); | ||
212 | clnt = NULL; | ||
213 | } | ||
206 | } | 214 | } |
207 | 215 | ||
208 | mutex_unlock(&host->h_mutex); | 216 | mutex_unlock(&host->h_mutex); |
209 | return clnt; | 217 | return clnt; |
210 | |||
211 | forgetit: | ||
212 | printk("lockd: couldn't create RPC handle for %s\n", host->h_name); | ||
213 | mutex_unlock(&host->h_mutex); | ||
214 | return NULL; | ||
215 | } | 218 | } |
216 | 219 | ||
217 | /* | 220 | /* |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 3fc683f46b3e..5954dcb497e4 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -109,30 +109,23 @@ nsm_unmonitor(struct nlm_host *host) | |||
109 | static struct rpc_clnt * | 109 | static struct rpc_clnt * |
110 | nsm_create(void) | 110 | nsm_create(void) |
111 | { | 111 | { |
112 | struct rpc_xprt *xprt; | 112 | struct sockaddr_in sin = { |
113 | struct rpc_clnt *clnt; | 113 | .sin_family = AF_INET, |
114 | struct sockaddr_in sin; | 114 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), |
115 | 115 | .sin_port = 0, | |
116 | sin.sin_family = AF_INET; | 116 | }; |
117 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | 117 | struct rpc_create_args args = { |
118 | sin.sin_port = 0; | 118 | .protocol = IPPROTO_UDP, |
119 | 119 | .address = (struct sockaddr *)&sin, | |
120 | xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); | 120 | .addrsize = sizeof(sin), |
121 | if (IS_ERR(xprt)) | 121 | .servername = "localhost", |
122 | return (struct rpc_clnt *)xprt; | 122 | .program = &nsm_program, |
123 | xprt->resvport = 1; /* NSM requires a reserved port */ | 123 | .version = SM_VERSION, |
124 | 124 | .authflavor = RPC_AUTH_NULL, | |
125 | clnt = rpc_create_client(xprt, "localhost", | 125 | .flags = (RPC_CLNT_CREATE_ONESHOT), |
126 | &nsm_program, SM_VERSION, | 126 | }; |
127 | RPC_AUTH_NULL); | 127 | |
128 | if (IS_ERR(clnt)) | 128 | return rpc_create(&args); |
129 | goto out_err; | ||
130 | clnt->cl_softrtry = 1; | ||
131 | clnt->cl_oneshot = 1; | ||
132 | return clnt; | ||
133 | |||
134 | out_err: | ||
135 | return clnt; | ||
136 | } | 129 | } |
137 | 130 | ||
138 | /* | 131 | /* |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 0b572a0c1967..f4580b44eef4 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -4,9 +4,9 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_NFS_FS) += nfs.o | 5 | obj-$(CONFIG_NFS_FS) += nfs.o |
6 | 6 | ||
7 | nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \ | 7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ |
8 | proc.o read.o symlink.o unlink.o write.o \ | 8 | pagelist.o proc.o read.o symlink.o unlink.o \ |
9 | namespace.o | 9 | write.o namespace.o |
10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o | 10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o |
11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
12 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | 12 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index fe0a6b8ac149..a3ee11364db0 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include "nfs4_fs.h" | 20 | #include "nfs4_fs.h" |
21 | #include "callback.h" | 21 | #include "callback.h" |
22 | #include "internal.h" | ||
22 | 23 | ||
23 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 24 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
24 | 25 | ||
@@ -36,6 +37,21 @@ static struct svc_program nfs4_callback_program; | |||
36 | 37 | ||
37 | unsigned int nfs_callback_set_tcpport; | 38 | unsigned int nfs_callback_set_tcpport; |
38 | unsigned short nfs_callback_tcpport; | 39 | unsigned short nfs_callback_tcpport; |
40 | static const int nfs_set_port_min = 0; | ||
41 | static const int nfs_set_port_max = 65535; | ||
42 | |||
43 | static int param_set_port(const char *val, struct kernel_param *kp) | ||
44 | { | ||
45 | char *endp; | ||
46 | int num = simple_strtol(val, &endp, 0); | ||
47 | if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) | ||
48 | return -EINVAL; | ||
49 | *((int *)kp->arg) = num; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | module_param_call(callback_tcpport, param_set_port, param_get_int, | ||
54 | &nfs_callback_set_tcpport, 0644); | ||
39 | 55 | ||
40 | /* | 56 | /* |
41 | * This is the callback kernel thread. | 57 | * This is the callback kernel thread. |
@@ -134,10 +150,8 @@ out_err: | |||
134 | /* | 150 | /* |
135 | * Kill the server process if it is not already up. | 151 | * Kill the server process if it is not already up. |
136 | */ | 152 | */ |
137 | int nfs_callback_down(void) | 153 | void nfs_callback_down(void) |
138 | { | 154 | { |
139 | int ret = 0; | ||
140 | |||
141 | lock_kernel(); | 155 | lock_kernel(); |
142 | mutex_lock(&nfs_callback_mutex); | 156 | mutex_lock(&nfs_callback_mutex); |
143 | nfs_callback_info.users--; | 157 | nfs_callback_info.users--; |
@@ -149,20 +163,19 @@ int nfs_callback_down(void) | |||
149 | } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); | 163 | } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); |
150 | mutex_unlock(&nfs_callback_mutex); | 164 | mutex_unlock(&nfs_callback_mutex); |
151 | unlock_kernel(); | 165 | unlock_kernel(); |
152 | return ret; | ||
153 | } | 166 | } |
154 | 167 | ||
155 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 168 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
156 | { | 169 | { |
157 | struct in_addr *addr = &rqstp->rq_addr.sin_addr; | 170 | struct sockaddr_in *addr = &rqstp->rq_addr; |
158 | struct nfs4_client *clp; | 171 | struct nfs_client *clp; |
159 | 172 | ||
160 | /* Don't talk to strangers */ | 173 | /* Don't talk to strangers */ |
161 | clp = nfs4_find_client(addr); | 174 | clp = nfs_find_client(addr, 4); |
162 | if (clp == NULL) | 175 | if (clp == NULL) |
163 | return SVC_DROP; | 176 | return SVC_DROP; |
164 | dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr)); | 177 | dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr->sin_addr)); |
165 | nfs4_put_client(clp); | 178 | nfs_put_client(clp); |
166 | switch (rqstp->rq_authop->flavour) { | 179 | switch (rqstp->rq_authop->flavour) { |
167 | case RPC_AUTH_NULL: | 180 | case RPC_AUTH_NULL: |
168 | if (rqstp->rq_proc != CB_NULL) | 181 | if (rqstp->rq_proc != CB_NULL) |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index b252e7fe53a5..5676163d26e8 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -62,8 +62,13 @@ struct cb_recallargs { | |||
62 | extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 62 | extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
63 | extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | 63 | extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); |
64 | 64 | ||
65 | #ifdef CONFIG_NFS_V4 | ||
65 | extern int nfs_callback_up(void); | 66 | extern int nfs_callback_up(void); |
66 | extern int nfs_callback_down(void); | 67 | extern void nfs_callback_down(void); |
68 | #else | ||
69 | #define nfs_callback_up() (0) | ||
70 | #define nfs_callback_down() do {} while(0) | ||
71 | #endif | ||
67 | 72 | ||
68 | extern unsigned int nfs_callback_set_tcpport; | 73 | extern unsigned int nfs_callback_set_tcpport; |
69 | extern unsigned short nfs_callback_tcpport; | 74 | extern unsigned short nfs_callback_tcpport; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 7719483ecdfc..97cf8f71451f 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -10,19 +10,20 @@ | |||
10 | #include "nfs4_fs.h" | 10 | #include "nfs4_fs.h" |
11 | #include "callback.h" | 11 | #include "callback.h" |
12 | #include "delegation.h" | 12 | #include "delegation.h" |
13 | #include "internal.h" | ||
13 | 14 | ||
14 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 15 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
15 | 16 | ||
16 | unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) | 17 | unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) |
17 | { | 18 | { |
18 | struct nfs4_client *clp; | 19 | struct nfs_client *clp; |
19 | struct nfs_delegation *delegation; | 20 | struct nfs_delegation *delegation; |
20 | struct nfs_inode *nfsi; | 21 | struct nfs_inode *nfsi; |
21 | struct inode *inode; | 22 | struct inode *inode; |
22 | 23 | ||
23 | res->bitmap[0] = res->bitmap[1] = 0; | 24 | res->bitmap[0] = res->bitmap[1] = 0; |
24 | res->status = htonl(NFS4ERR_BADHANDLE); | 25 | res->status = htonl(NFS4ERR_BADHANDLE); |
25 | clp = nfs4_find_client(&args->addr->sin_addr); | 26 | clp = nfs_find_client(args->addr, 4); |
26 | if (clp == NULL) | 27 | if (clp == NULL) |
27 | goto out; | 28 | goto out; |
28 | inode = nfs_delegation_find_inode(clp, &args->fh); | 29 | inode = nfs_delegation_find_inode(clp, &args->fh); |
@@ -48,7 +49,7 @@ out_iput: | |||
48 | up_read(&nfsi->rwsem); | 49 | up_read(&nfsi->rwsem); |
49 | iput(inode); | 50 | iput(inode); |
50 | out_putclient: | 51 | out_putclient: |
51 | nfs4_put_client(clp); | 52 | nfs_put_client(clp); |
52 | out: | 53 | out: |
53 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status)); | 54 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status)); |
54 | return res->status; | 55 | return res->status; |
@@ -56,12 +57,12 @@ out: | |||
56 | 57 | ||
57 | unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | 58 | unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) |
58 | { | 59 | { |
59 | struct nfs4_client *clp; | 60 | struct nfs_client *clp; |
60 | struct inode *inode; | 61 | struct inode *inode; |
61 | unsigned res; | 62 | unsigned res; |
62 | 63 | ||
63 | res = htonl(NFS4ERR_BADHANDLE); | 64 | res = htonl(NFS4ERR_BADHANDLE); |
64 | clp = nfs4_find_client(&args->addr->sin_addr); | 65 | clp = nfs_find_client(args->addr, 4); |
65 | if (clp == NULL) | 66 | if (clp == NULL) |
66 | goto out; | 67 | goto out; |
67 | inode = nfs_delegation_find_inode(clp, &args->fh); | 68 | inode = nfs_delegation_find_inode(clp, &args->fh); |
@@ -80,7 +81,7 @@ unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | |||
80 | } | 81 | } |
81 | iput(inode); | 82 | iput(inode); |
82 | out_putclient: | 83 | out_putclient: |
83 | nfs4_put_client(clp); | 84 | nfs_put_client(clp); |
84 | out: | 85 | out: |
85 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); | 86 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); |
86 | return res; | 87 | return res; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c new file mode 100644 index 000000000000..ec1938d4b814 --- /dev/null +++ b/fs/nfs/client.c | |||
@@ -0,0 +1,1448 @@ | |||
1 | /* client.c: NFS client sharing and management code | ||
2 | * | ||
3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | |||
17 | #include <linux/time.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/stat.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/unistd.h> | ||
24 | #include <linux/sunrpc/clnt.h> | ||
25 | #include <linux/sunrpc/stats.h> | ||
26 | #include <linux/sunrpc/metrics.h> | ||
27 | #include <linux/nfs_fs.h> | ||
28 | #include <linux/nfs_mount.h> | ||
29 | #include <linux/nfs4_mount.h> | ||
30 | #include <linux/lockd/bind.h> | ||
31 | #include <linux/smp_lock.h> | ||
32 | #include <linux/seq_file.h> | ||
33 | #include <linux/mount.h> | ||
34 | #include <linux/nfs_idmap.h> | ||
35 | #include <linux/vfs.h> | ||
36 | #include <linux/inet.h> | ||
37 | #include <linux/nfs_xdr.h> | ||
38 | |||
39 | #include <asm/system.h> | ||
40 | |||
41 | #include "nfs4_fs.h" | ||
42 | #include "callback.h" | ||
43 | #include "delegation.h" | ||
44 | #include "iostat.h" | ||
45 | #include "internal.h" | ||
46 | |||
47 | #define NFSDBG_FACILITY NFSDBG_CLIENT | ||
48 | |||
49 | static DEFINE_SPINLOCK(nfs_client_lock); | ||
50 | static LIST_HEAD(nfs_client_list); | ||
51 | static LIST_HEAD(nfs_volume_list); | ||
52 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | ||
53 | |||
54 | /* | ||
55 | * RPC cruft for NFS | ||
56 | */ | ||
57 | static struct rpc_version *nfs_version[5] = { | ||
58 | [2] = &nfs_version2, | ||
59 | #ifdef CONFIG_NFS_V3 | ||
60 | [3] = &nfs_version3, | ||
61 | #endif | ||
62 | #ifdef CONFIG_NFS_V4 | ||
63 | [4] = &nfs_version4, | ||
64 | #endif | ||
65 | }; | ||
66 | |||
67 | struct rpc_program nfs_program = { | ||
68 | .name = "nfs", | ||
69 | .number = NFS_PROGRAM, | ||
70 | .nrvers = ARRAY_SIZE(nfs_version), | ||
71 | .version = nfs_version, | ||
72 | .stats = &nfs_rpcstat, | ||
73 | .pipe_dir_name = "/nfs", | ||
74 | }; | ||
75 | |||
76 | struct rpc_stat nfs_rpcstat = { | ||
77 | .program = &nfs_program | ||
78 | }; | ||
79 | |||
80 | |||
81 | #ifdef CONFIG_NFS_V3_ACL | ||
82 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | ||
83 | static struct rpc_version * nfsacl_version[] = { | ||
84 | [3] = &nfsacl_version3, | ||
85 | }; | ||
86 | |||
87 | struct rpc_program nfsacl_program = { | ||
88 | .name = "nfsacl", | ||
89 | .number = NFS_ACL_PROGRAM, | ||
90 | .nrvers = ARRAY_SIZE(nfsacl_version), | ||
91 | .version = nfsacl_version, | ||
92 | .stats = &nfsacl_rpcstat, | ||
93 | }; | ||
94 | #endif /* CONFIG_NFS_V3_ACL */ | ||
95 | |||
96 | /* | ||
97 | * Allocate a shared client record | ||
98 | * | ||
99 | * Since these are allocated/deallocated very rarely, we don't | ||
100 | * bother putting them in a slab cache... | ||
101 | */ | ||
102 | static struct nfs_client *nfs_alloc_client(const char *hostname, | ||
103 | const struct sockaddr_in *addr, | ||
104 | int nfsversion) | ||
105 | { | ||
106 | struct nfs_client *clp; | ||
107 | int error; | ||
108 | |||
109 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | ||
110 | goto error_0; | ||
111 | |||
112 | error = rpciod_up(); | ||
113 | if (error < 0) { | ||
114 | dprintk("%s: couldn't start rpciod! Error = %d\n", | ||
115 | __FUNCTION__, error); | ||
116 | goto error_1; | ||
117 | } | ||
118 | __set_bit(NFS_CS_RPCIOD, &clp->cl_res_state); | ||
119 | |||
120 | if (nfsversion == 4) { | ||
121 | if (nfs_callback_up() < 0) | ||
122 | goto error_2; | ||
123 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
124 | } | ||
125 | |||
126 | atomic_set(&clp->cl_count, 1); | ||
127 | clp->cl_cons_state = NFS_CS_INITING; | ||
128 | |||
129 | clp->cl_nfsversion = nfsversion; | ||
130 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | ||
131 | |||
132 | if (hostname) { | ||
133 | clp->cl_hostname = kstrdup(hostname, GFP_KERNEL); | ||
134 | if (!clp->cl_hostname) | ||
135 | goto error_3; | ||
136 | } | ||
137 | |||
138 | INIT_LIST_HEAD(&clp->cl_superblocks); | ||
139 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
140 | |||
141 | #ifdef CONFIG_NFS_V4 | ||
142 | init_rwsem(&clp->cl_sem); | ||
143 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
144 | INIT_LIST_HEAD(&clp->cl_state_owners); | ||
145 | INIT_LIST_HEAD(&clp->cl_unused); | ||
146 | spin_lock_init(&clp->cl_lock); | ||
147 | INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); | ||
148 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | ||
149 | clp->cl_boot_time = CURRENT_TIME; | ||
150 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | ||
151 | #endif | ||
152 | |||
153 | return clp; | ||
154 | |||
155 | error_3: | ||
156 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
157 | nfs_callback_down(); | ||
158 | error_2: | ||
159 | rpciod_down(); | ||
160 | __clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state); | ||
161 | error_1: | ||
162 | kfree(clp); | ||
163 | error_0: | ||
164 | return NULL; | ||
165 | } | ||
166 | |||
167 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
168 | { | ||
169 | #ifdef CONFIG_NFS_V4 | ||
170 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | ||
171 | nfs4_kill_renewd(clp); | ||
172 | while (!list_empty(&clp->cl_unused)) { | ||
173 | struct nfs4_state_owner *sp; | ||
174 | |||
175 | sp = list_entry(clp->cl_unused.next, | ||
176 | struct nfs4_state_owner, | ||
177 | so_list); | ||
178 | list_del(&sp->so_list); | ||
179 | kfree(sp); | ||
180 | } | ||
181 | BUG_ON(!list_empty(&clp->cl_state_owners)); | ||
182 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | ||
183 | nfs_idmap_delete(clp); | ||
184 | #endif | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * Destroy a shared client record | ||
189 | */ | ||
190 | static void nfs_free_client(struct nfs_client *clp) | ||
191 | { | ||
192 | dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion); | ||
193 | |||
194 | nfs4_shutdown_client(clp); | ||
195 | |||
196 | /* -EIO all pending I/O */ | ||
197 | if (!IS_ERR(clp->cl_rpcclient)) | ||
198 | rpc_shutdown_client(clp->cl_rpcclient); | ||
199 | |||
200 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
201 | nfs_callback_down(); | ||
202 | |||
203 | if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state)) | ||
204 | rpciod_down(); | ||
205 | |||
206 | kfree(clp->cl_hostname); | ||
207 | kfree(clp); | ||
208 | |||
209 | dprintk("<-- nfs_free_client()\n"); | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * Release a reference to a shared client record | ||
214 | */ | ||
215 | void nfs_put_client(struct nfs_client *clp) | ||
216 | { | ||
217 | if (!clp) | ||
218 | return; | ||
219 | |||
220 | dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); | ||
221 | |||
222 | if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { | ||
223 | list_del(&clp->cl_share_link); | ||
224 | spin_unlock(&nfs_client_lock); | ||
225 | |||
226 | BUG_ON(!list_empty(&clp->cl_superblocks)); | ||
227 | |||
228 | nfs_free_client(clp); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Find a client by address | ||
234 | * - caller must hold nfs_client_lock | ||
235 | */ | ||
236 | static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion) | ||
237 | { | ||
238 | struct nfs_client *clp; | ||
239 | |||
240 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
241 | /* Different NFS versions cannot share the same nfs_client */ | ||
242 | if (clp->cl_nfsversion != nfsversion) | ||
243 | continue; | ||
244 | |||
245 | if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr, | ||
246 | sizeof(clp->cl_addr.sin_addr)) != 0) | ||
247 | continue; | ||
248 | |||
249 | if (clp->cl_addr.sin_port == addr->sin_port) | ||
250 | goto found; | ||
251 | } | ||
252 | |||
253 | return NULL; | ||
254 | |||
255 | found: | ||
256 | atomic_inc(&clp->cl_count); | ||
257 | return clp; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Find a client by IP address and protocol version | ||
262 | * - returns NULL if no such client | ||
263 | */ | ||
264 | struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion) | ||
265 | { | ||
266 | struct nfs_client *clp; | ||
267 | |||
268 | spin_lock(&nfs_client_lock); | ||
269 | clp = __nfs_find_client(addr, nfsversion); | ||
270 | spin_unlock(&nfs_client_lock); | ||
271 | |||
272 | BUG_ON(clp && clp->cl_cons_state == 0); | ||
273 | |||
274 | return clp; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * Look up a client by IP address and protocol version | ||
279 | * - creates a new record if one doesn't yet exist | ||
280 | */ | ||
281 | static struct nfs_client *nfs_get_client(const char *hostname, | ||
282 | const struct sockaddr_in *addr, | ||
283 | int nfsversion) | ||
284 | { | ||
285 | struct nfs_client *clp, *new = NULL; | ||
286 | int error; | ||
287 | |||
288 | dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n", | ||
289 | hostname ?: "", NIPQUAD(addr->sin_addr), | ||
290 | addr->sin_port, nfsversion); | ||
291 | |||
292 | /* see if the client already exists */ | ||
293 | do { | ||
294 | spin_lock(&nfs_client_lock); | ||
295 | |||
296 | clp = __nfs_find_client(addr, nfsversion); | ||
297 | if (clp) | ||
298 | goto found_client; | ||
299 | if (new) | ||
300 | goto install_client; | ||
301 | |||
302 | spin_unlock(&nfs_client_lock); | ||
303 | |||
304 | new = nfs_alloc_client(hostname, addr, nfsversion); | ||
305 | } while (new); | ||
306 | |||
307 | return ERR_PTR(-ENOMEM); | ||
308 | |||
309 | /* install a new client and return with it unready */ | ||
310 | install_client: | ||
311 | clp = new; | ||
312 | list_add(&clp->cl_share_link, &nfs_client_list); | ||
313 | spin_unlock(&nfs_client_lock); | ||
314 | dprintk("--> nfs_get_client() = %p [new]\n", clp); | ||
315 | return clp; | ||
316 | |||
317 | /* found an existing client | ||
318 | * - make sure it's ready before returning | ||
319 | */ | ||
320 | found_client: | ||
321 | spin_unlock(&nfs_client_lock); | ||
322 | |||
323 | if (new) | ||
324 | nfs_free_client(new); | ||
325 | |||
326 | if (clp->cl_cons_state == NFS_CS_INITING) { | ||
327 | DECLARE_WAITQUEUE(myself, current); | ||
328 | |||
329 | add_wait_queue(&nfs_client_active_wq, &myself); | ||
330 | |||
331 | for (;;) { | ||
332 | set_current_state(TASK_INTERRUPTIBLE); | ||
333 | if (signal_pending(current) || | ||
334 | clp->cl_cons_state > NFS_CS_READY) | ||
335 | break; | ||
336 | schedule(); | ||
337 | } | ||
338 | |||
339 | remove_wait_queue(&nfs_client_active_wq, &myself); | ||
340 | |||
341 | if (signal_pending(current)) { | ||
342 | nfs_put_client(clp); | ||
343 | return ERR_PTR(-ERESTARTSYS); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if (clp->cl_cons_state < NFS_CS_READY) { | ||
348 | error = clp->cl_cons_state; | ||
349 | nfs_put_client(clp); | ||
350 | return ERR_PTR(error); | ||
351 | } | ||
352 | |||
353 | BUG_ON(clp->cl_cons_state != NFS_CS_READY); | ||
354 | |||
355 | dprintk("--> nfs_get_client() = %p [share]\n", clp); | ||
356 | return clp; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * Mark a server as ready or failed | ||
361 | */ | ||
362 | static void nfs_mark_client_ready(struct nfs_client *clp, int state) | ||
363 | { | ||
364 | clp->cl_cons_state = state; | ||
365 | wake_up_all(&nfs_client_active_wq); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Initialise the timeout values for a connection | ||
370 | */ | ||
371 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | ||
372 | unsigned int timeo, unsigned int retrans) | ||
373 | { | ||
374 | to->to_initval = timeo * HZ / 10; | ||
375 | to->to_retries = retrans; | ||
376 | if (!to->to_retries) | ||
377 | to->to_retries = 2; | ||
378 | |||
379 | switch (proto) { | ||
380 | case IPPROTO_TCP: | ||
381 | if (!to->to_initval) | ||
382 | to->to_initval = 60 * HZ; | ||
383 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) | ||
384 | to->to_initval = NFS_MAX_TCP_TIMEOUT; | ||
385 | to->to_increment = to->to_initval; | ||
386 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); | ||
387 | to->to_exponential = 0; | ||
388 | break; | ||
389 | case IPPROTO_UDP: | ||
390 | default: | ||
391 | if (!to->to_initval) | ||
392 | to->to_initval = 11 * HZ / 10; | ||
393 | if (to->to_initval > NFS_MAX_UDP_TIMEOUT) | ||
394 | to->to_initval = NFS_MAX_UDP_TIMEOUT; | ||
395 | to->to_maxval = NFS_MAX_UDP_TIMEOUT; | ||
396 | to->to_exponential = 1; | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Create an RPC client handle | ||
403 | */ | ||
404 | static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | ||
405 | unsigned int timeo, | ||
406 | unsigned int retrans, | ||
407 | rpc_authflavor_t flavor) | ||
408 | { | ||
409 | struct rpc_timeout timeparms; | ||
410 | struct rpc_clnt *clnt = NULL; | ||
411 | struct rpc_create_args args = { | ||
412 | .protocol = proto, | ||
413 | .address = (struct sockaddr *)&clp->cl_addr, | ||
414 | .addrsize = sizeof(clp->cl_addr), | ||
415 | .timeout = &timeparms, | ||
416 | .servername = clp->cl_hostname, | ||
417 | .program = &nfs_program, | ||
418 | .version = clp->rpc_ops->version, | ||
419 | .authflavor = flavor, | ||
420 | }; | ||
421 | |||
422 | if (!IS_ERR(clp->cl_rpcclient)) | ||
423 | return 0; | ||
424 | |||
425 | nfs_init_timeout_values(&timeparms, proto, timeo, retrans); | ||
426 | clp->retrans_timeo = timeparms.to_initval; | ||
427 | clp->retrans_count = timeparms.to_retries; | ||
428 | |||
429 | clnt = rpc_create(&args); | ||
430 | if (IS_ERR(clnt)) { | ||
431 | dprintk("%s: cannot create RPC client. Error = %ld\n", | ||
432 | __FUNCTION__, PTR_ERR(clnt)); | ||
433 | return PTR_ERR(clnt); | ||
434 | } | ||
435 | |||
436 | clp->cl_rpcclient = clnt; | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * Version 2 or 3 client destruction | ||
442 | */ | ||
443 | static void nfs_destroy_server(struct nfs_server *server) | ||
444 | { | ||
445 | if (!IS_ERR(server->client_acl)) | ||
446 | rpc_shutdown_client(server->client_acl); | ||
447 | |||
448 | if (!(server->flags & NFS_MOUNT_NONLM)) | ||
449 | lockd_down(); /* release rpc.lockd */ | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * Version 2 or 3 lockd setup | ||
454 | */ | ||
455 | static int nfs_start_lockd(struct nfs_server *server) | ||
456 | { | ||
457 | int error = 0; | ||
458 | |||
459 | if (server->nfs_client->cl_nfsversion > 3) | ||
460 | goto out; | ||
461 | if (server->flags & NFS_MOUNT_NONLM) | ||
462 | goto out; | ||
463 | error = lockd_up(); | ||
464 | if (error < 0) | ||
465 | server->flags |= NFS_MOUNT_NONLM; | ||
466 | else | ||
467 | server->destroy = nfs_destroy_server; | ||
468 | out: | ||
469 | return error; | ||
470 | } | ||
471 | |||
472 | /* | ||
473 | * Initialise an NFSv3 ACL client connection | ||
474 | */ | ||
475 | #ifdef CONFIG_NFS_V3_ACL | ||
476 | static void nfs_init_server_aclclient(struct nfs_server *server) | ||
477 | { | ||
478 | if (server->nfs_client->cl_nfsversion != 3) | ||
479 | goto out_noacl; | ||
480 | if (server->flags & NFS_MOUNT_NOACL) | ||
481 | goto out_noacl; | ||
482 | |||
483 | server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); | ||
484 | if (IS_ERR(server->client_acl)) | ||
485 | goto out_noacl; | ||
486 | |||
487 | /* No errors! Assume that Sun nfsacls are supported */ | ||
488 | server->caps |= NFS_CAP_ACLS; | ||
489 | return; | ||
490 | |||
491 | out_noacl: | ||
492 | server->caps &= ~NFS_CAP_ACLS; | ||
493 | } | ||
494 | #else | ||
495 | static inline void nfs_init_server_aclclient(struct nfs_server *server) | ||
496 | { | ||
497 | server->flags &= ~NFS_MOUNT_NOACL; | ||
498 | server->caps &= ~NFS_CAP_ACLS; | ||
499 | } | ||
500 | #endif | ||
501 | |||
502 | /* | ||
503 | * Create a general RPC client | ||
504 | */ | ||
505 | static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour) | ||
506 | { | ||
507 | struct nfs_client *clp = server->nfs_client; | ||
508 | |||
509 | server->client = rpc_clone_client(clp->cl_rpcclient); | ||
510 | if (IS_ERR(server->client)) { | ||
511 | dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__); | ||
512 | return PTR_ERR(server->client); | ||
513 | } | ||
514 | |||
515 | if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) { | ||
516 | struct rpc_auth *auth; | ||
517 | |||
518 | auth = rpcauth_create(pseudoflavour, server->client); | ||
519 | if (IS_ERR(auth)) { | ||
520 | dprintk("%s: couldn't create credcache!\n", __FUNCTION__); | ||
521 | return PTR_ERR(auth); | ||
522 | } | ||
523 | } | ||
524 | server->client->cl_softrtry = 0; | ||
525 | if (server->flags & NFS_MOUNT_SOFT) | ||
526 | server->client->cl_softrtry = 1; | ||
527 | |||
528 | server->client->cl_intr = 0; | ||
529 | if (server->flags & NFS4_MOUNT_INTR) | ||
530 | server->client->cl_intr = 1; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * Initialise an NFS2 or NFS3 client | ||
537 | */ | ||
538 | static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data) | ||
539 | { | ||
540 | int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP; | ||
541 | int error; | ||
542 | |||
543 | if (clp->cl_cons_state == NFS_CS_READY) { | ||
544 | /* the client is already initialised */ | ||
545 | dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp); | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
550 | clp->rpc_ops = &nfs_v2_clientops; | ||
551 | #ifdef CONFIG_NFS_V3 | ||
552 | if (clp->cl_nfsversion == 3) | ||
553 | clp->rpc_ops = &nfs_v3_clientops; | ||
554 | #endif | ||
555 | /* | ||
556 | * Create a client RPC handle for doing FSSTAT with UNIX auth only | ||
557 | * - RFC 2623, sec 2.3.2 | ||
558 | */ | ||
559 | error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans, | ||
560 | RPC_AUTH_UNIX); | ||
561 | if (error < 0) | ||
562 | goto error; | ||
563 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
564 | return 0; | ||
565 | |||
566 | error: | ||
567 | nfs_mark_client_ready(clp, error); | ||
568 | dprintk("<-- nfs_init_client() = xerror %d\n", error); | ||
569 | return error; | ||
570 | } | ||
571 | |||
572 | /* | ||
573 | * Create a version 2 or 3 client | ||
574 | */ | ||
575 | static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data) | ||
576 | { | ||
577 | struct nfs_client *clp; | ||
578 | int error, nfsvers = 2; | ||
579 | |||
580 | dprintk("--> nfs_init_server()\n"); | ||
581 | |||
582 | #ifdef CONFIG_NFS_V3 | ||
583 | if (data->flags & NFS_MOUNT_VER3) | ||
584 | nfsvers = 3; | ||
585 | #endif | ||
586 | |||
587 | /* Allocate or find a client reference we can use */ | ||
588 | clp = nfs_get_client(data->hostname, &data->addr, nfsvers); | ||
589 | if (IS_ERR(clp)) { | ||
590 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); | ||
591 | return PTR_ERR(clp); | ||
592 | } | ||
593 | |||
594 | error = nfs_init_client(clp, data); | ||
595 | if (error < 0) | ||
596 | goto error; | ||
597 | |||
598 | server->nfs_client = clp; | ||
599 | |||
600 | /* Initialise the client representation from the mount data */ | ||
601 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | ||
602 | |||
603 | if (data->rsize) | ||
604 | server->rsize = nfs_block_size(data->rsize, NULL); | ||
605 | if (data->wsize) | ||
606 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
607 | |||
608 | server->acregmin = data->acregmin * HZ; | ||
609 | server->acregmax = data->acregmax * HZ; | ||
610 | server->acdirmin = data->acdirmin * HZ; | ||
611 | server->acdirmax = data->acdirmax * HZ; | ||
612 | |||
613 | /* Start lockd here, before we might error out */ | ||
614 | error = nfs_start_lockd(server); | ||
615 | if (error < 0) | ||
616 | goto error; | ||
617 | |||
618 | error = nfs_init_server_rpcclient(server, data->pseudoflavor); | ||
619 | if (error < 0) | ||
620 | goto error; | ||
621 | |||
622 | server->namelen = data->namlen; | ||
623 | /* Create a client RPC handle for the NFSv3 ACL management interface */ | ||
624 | nfs_init_server_aclclient(server); | ||
625 | if (clp->cl_nfsversion == 3) { | ||
626 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) | ||
627 | server->namelen = NFS3_MAXNAMLEN; | ||
628 | server->caps |= NFS_CAP_READDIRPLUS; | ||
629 | } else { | ||
630 | if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) | ||
631 | server->namelen = NFS2_MAXNAMLEN; | ||
632 | } | ||
633 | |||
634 | dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp); | ||
635 | return 0; | ||
636 | |||
637 | error: | ||
638 | server->nfs_client = NULL; | ||
639 | nfs_put_client(clp); | ||
640 | dprintk("<-- nfs_init_server() = xerror %d\n", error); | ||
641 | return error; | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * Load up the server record from information gained in an fsinfo record | ||
646 | */ | ||
647 | static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo) | ||
648 | { | ||
649 | unsigned long max_rpc_payload; | ||
650 | |||
651 | /* Work out a lot of parameters */ | ||
652 | if (server->rsize == 0) | ||
653 | server->rsize = nfs_block_size(fsinfo->rtpref, NULL); | ||
654 | if (server->wsize == 0) | ||
655 | server->wsize = nfs_block_size(fsinfo->wtpref, NULL); | ||
656 | |||
657 | if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax) | ||
658 | server->rsize = nfs_block_size(fsinfo->rtmax, NULL); | ||
659 | if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax) | ||
660 | server->wsize = nfs_block_size(fsinfo->wtmax, NULL); | ||
661 | |||
662 | max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); | ||
663 | if (server->rsize > max_rpc_payload) | ||
664 | server->rsize = max_rpc_payload; | ||
665 | if (server->rsize > NFS_MAX_FILE_IO_SIZE) | ||
666 | server->rsize = NFS_MAX_FILE_IO_SIZE; | ||
667 | server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
668 | server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; | ||
669 | |||
670 | if (server->wsize > max_rpc_payload) | ||
671 | server->wsize = max_rpc_payload; | ||
672 | if (server->wsize > NFS_MAX_FILE_IO_SIZE) | ||
673 | server->wsize = NFS_MAX_FILE_IO_SIZE; | ||
674 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
675 | server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL); | ||
676 | |||
677 | server->dtsize = nfs_block_size(fsinfo->dtpref, NULL); | ||
678 | if (server->dtsize > PAGE_CACHE_SIZE) | ||
679 | server->dtsize = PAGE_CACHE_SIZE; | ||
680 | if (server->dtsize > server->rsize) | ||
681 | server->dtsize = server->rsize; | ||
682 | |||
683 | if (server->flags & NFS_MOUNT_NOAC) { | ||
684 | server->acregmin = server->acregmax = 0; | ||
685 | server->acdirmin = server->acdirmax = 0; | ||
686 | } | ||
687 | |||
688 | server->maxfilesize = fsinfo->maxfilesize; | ||
689 | |||
690 | /* We're airborne Set socket buffersize */ | ||
691 | rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); | ||
692 | } | ||
693 | |||
694 | /* | ||
695 | * Probe filesystem information, including the FSID on v2/v3 | ||
696 | */ | ||
697 | static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr) | ||
698 | { | ||
699 | struct nfs_fsinfo fsinfo; | ||
700 | struct nfs_client *clp = server->nfs_client; | ||
701 | int error; | ||
702 | |||
703 | dprintk("--> nfs_probe_fsinfo()\n"); | ||
704 | |||
705 | if (clp->rpc_ops->set_capabilities != NULL) { | ||
706 | error = clp->rpc_ops->set_capabilities(server, mntfh); | ||
707 | if (error < 0) | ||
708 | goto out_error; | ||
709 | } | ||
710 | |||
711 | fsinfo.fattr = fattr; | ||
712 | nfs_fattr_init(fattr); | ||
713 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); | ||
714 | if (error < 0) | ||
715 | goto out_error; | ||
716 | |||
717 | nfs_server_set_fsinfo(server, &fsinfo); | ||
718 | |||
719 | /* Get some general file system info */ | ||
720 | if (server->namelen == 0) { | ||
721 | struct nfs_pathconf pathinfo; | ||
722 | |||
723 | pathinfo.fattr = fattr; | ||
724 | nfs_fattr_init(fattr); | ||
725 | |||
726 | if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0) | ||
727 | server->namelen = pathinfo.max_namelen; | ||
728 | } | ||
729 | |||
730 | dprintk("<-- nfs_probe_fsinfo() = 0\n"); | ||
731 | return 0; | ||
732 | |||
733 | out_error: | ||
734 | dprintk("nfs_probe_fsinfo: error = %d\n", -error); | ||
735 | return error; | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * Copy useful information when duplicating a server record | ||
740 | */ | ||
741 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) | ||
742 | { | ||
743 | target->flags = source->flags; | ||
744 | target->acregmin = source->acregmin; | ||
745 | target->acregmax = source->acregmax; | ||
746 | target->acdirmin = source->acdirmin; | ||
747 | target->acdirmax = source->acdirmax; | ||
748 | target->caps = source->caps; | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * Allocate and initialise a server record | ||
753 | */ | ||
754 | static struct nfs_server *nfs_alloc_server(void) | ||
755 | { | ||
756 | struct nfs_server *server; | ||
757 | |||
758 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); | ||
759 | if (!server) | ||
760 | return NULL; | ||
761 | |||
762 | server->client = server->client_acl = ERR_PTR(-EINVAL); | ||
763 | |||
764 | /* Zero out the NFS state stuff */ | ||
765 | INIT_LIST_HEAD(&server->client_link); | ||
766 | INIT_LIST_HEAD(&server->master_link); | ||
767 | |||
768 | server->io_stats = nfs_alloc_iostats(); | ||
769 | if (!server->io_stats) { | ||
770 | kfree(server); | ||
771 | return NULL; | ||
772 | } | ||
773 | |||
774 | return server; | ||
775 | } | ||
776 | |||
777 | /* | ||
778 | * Free up a server record | ||
779 | */ | ||
780 | void nfs_free_server(struct nfs_server *server) | ||
781 | { | ||
782 | dprintk("--> nfs_free_server()\n"); | ||
783 | |||
784 | spin_lock(&nfs_client_lock); | ||
785 | list_del(&server->client_link); | ||
786 | list_del(&server->master_link); | ||
787 | spin_unlock(&nfs_client_lock); | ||
788 | |||
789 | if (server->destroy != NULL) | ||
790 | server->destroy(server); | ||
791 | if (!IS_ERR(server->client)) | ||
792 | rpc_shutdown_client(server->client); | ||
793 | |||
794 | nfs_put_client(server->nfs_client); | ||
795 | |||
796 | nfs_free_iostats(server->io_stats); | ||
797 | kfree(server); | ||
798 | nfs_release_automount_timer(); | ||
799 | dprintk("<-- nfs_free_server()\n"); | ||
800 | } | ||
801 | |||
802 | /* | ||
803 | * Create a version 2 or 3 volume record | ||
804 | * - keyed on server and FSID | ||
805 | */ | ||
806 | struct nfs_server *nfs_create_server(const struct nfs_mount_data *data, | ||
807 | struct nfs_fh *mntfh) | ||
808 | { | ||
809 | struct nfs_server *server; | ||
810 | struct nfs_fattr fattr; | ||
811 | int error; | ||
812 | |||
813 | server = nfs_alloc_server(); | ||
814 | if (!server) | ||
815 | return ERR_PTR(-ENOMEM); | ||
816 | |||
817 | /* Get a client representation */ | ||
818 | error = nfs_init_server(server, data); | ||
819 | if (error < 0) | ||
820 | goto error; | ||
821 | |||
822 | BUG_ON(!server->nfs_client); | ||
823 | BUG_ON(!server->nfs_client->rpc_ops); | ||
824 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
825 | |||
826 | /* Probe the root fh to retrieve its FSID */ | ||
827 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | ||
828 | if (error < 0) | ||
829 | goto error; | ||
830 | if (!(fattr.valid & NFS_ATTR_FATTR)) { | ||
831 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | ||
832 | if (error < 0) { | ||
833 | dprintk("nfs_create_server: getattr error = %d\n", -error); | ||
834 | goto error; | ||
835 | } | ||
836 | } | ||
837 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | ||
838 | |||
839 | dprintk("Server FSID: %llx:%llx\n", | ||
840 | (unsigned long long) server->fsid.major, | ||
841 | (unsigned long long) server->fsid.minor); | ||
842 | |||
843 | BUG_ON(!server->nfs_client); | ||
844 | BUG_ON(!server->nfs_client->rpc_ops); | ||
845 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
846 | |||
847 | spin_lock(&nfs_client_lock); | ||
848 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
849 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
850 | spin_unlock(&nfs_client_lock); | ||
851 | |||
852 | server->mount_time = jiffies; | ||
853 | return server; | ||
854 | |||
855 | error: | ||
856 | nfs_free_server(server); | ||
857 | return ERR_PTR(error); | ||
858 | } | ||
859 | |||
860 | #ifdef CONFIG_NFS_V4 | ||
861 | /* | ||
862 | * Initialise an NFS4 client record | ||
863 | */ | ||
864 | static int nfs4_init_client(struct nfs_client *clp, | ||
865 | int proto, int timeo, int retrans, | ||
866 | rpc_authflavor_t authflavour) | ||
867 | { | ||
868 | int error; | ||
869 | |||
870 | if (clp->cl_cons_state == NFS_CS_READY) { | ||
871 | /* the client is initialised already */ | ||
872 | dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp); | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
877 | clp->rpc_ops = &nfs_v4_clientops; | ||
878 | |||
879 | error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour); | ||
880 | if (error < 0) | ||
881 | goto error; | ||
882 | |||
883 | error = nfs_idmap_new(clp); | ||
884 | if (error < 0) { | ||
885 | dprintk("%s: failed to create idmapper. Error = %d\n", | ||
886 | __FUNCTION__, error); | ||
887 | goto error; | ||
888 | } | ||
889 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | ||
890 | |||
891 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
892 | return 0; | ||
893 | |||
894 | error: | ||
895 | nfs_mark_client_ready(clp, error); | ||
896 | dprintk("<-- nfs4_init_client() = xerror %d\n", error); | ||
897 | return error; | ||
898 | } | ||
899 | |||
900 | /* | ||
901 | * Set up an NFS4 client | ||
902 | */ | ||
903 | static int nfs4_set_client(struct nfs_server *server, | ||
904 | const char *hostname, const struct sockaddr_in *addr, | ||
905 | rpc_authflavor_t authflavour, | ||
906 | int proto, int timeo, int retrans) | ||
907 | { | ||
908 | struct nfs_client *clp; | ||
909 | int error; | ||
910 | |||
911 | dprintk("--> nfs4_set_client()\n"); | ||
912 | |||
913 | /* Allocate or find a client reference we can use */ | ||
914 | clp = nfs_get_client(hostname, addr, 4); | ||
915 | if (IS_ERR(clp)) { | ||
916 | error = PTR_ERR(clp); | ||
917 | goto error; | ||
918 | } | ||
919 | error = nfs4_init_client(clp, proto, timeo, retrans, authflavour); | ||
920 | if (error < 0) | ||
921 | goto error_put; | ||
922 | |||
923 | server->nfs_client = clp; | ||
924 | dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp); | ||
925 | return 0; | ||
926 | |||
927 | error_put: | ||
928 | nfs_put_client(clp); | ||
929 | error: | ||
930 | dprintk("<-- nfs4_set_client() = xerror %d\n", error); | ||
931 | return error; | ||
932 | } | ||
933 | |||
934 | /* | ||
935 | * Create a version 4 volume record | ||
936 | */ | ||
937 | static int nfs4_init_server(struct nfs_server *server, | ||
938 | const struct nfs4_mount_data *data, rpc_authflavor_t authflavour) | ||
939 | { | ||
940 | int error; | ||
941 | |||
942 | dprintk("--> nfs4_init_server()\n"); | ||
943 | |||
944 | /* Initialise the client representation from the mount data */ | ||
945 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | ||
946 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
947 | |||
948 | if (data->rsize) | ||
949 | server->rsize = nfs_block_size(data->rsize, NULL); | ||
950 | if (data->wsize) | ||
951 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
952 | |||
953 | server->acregmin = data->acregmin * HZ; | ||
954 | server->acregmax = data->acregmax * HZ; | ||
955 | server->acdirmin = data->acdirmin * HZ; | ||
956 | server->acdirmax = data->acdirmax * HZ; | ||
957 | |||
958 | error = nfs_init_server_rpcclient(server, authflavour); | ||
959 | |||
960 | /* Done */ | ||
961 | dprintk("<-- nfs4_init_server() = %d\n", error); | ||
962 | return error; | ||
963 | } | ||
964 | |||
965 | /* | ||
966 | * Create a version 4 volume record | ||
967 | * - keyed on server and FSID | ||
968 | */ | ||
969 | struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, | ||
970 | const char *hostname, | ||
971 | const struct sockaddr_in *addr, | ||
972 | const char *mntpath, | ||
973 | const char *ip_addr, | ||
974 | rpc_authflavor_t authflavour, | ||
975 | struct nfs_fh *mntfh) | ||
976 | { | ||
977 | struct nfs_fattr fattr; | ||
978 | struct nfs_server *server; | ||
979 | int error; | ||
980 | |||
981 | dprintk("--> nfs4_create_server()\n"); | ||
982 | |||
983 | server = nfs_alloc_server(); | ||
984 | if (!server) | ||
985 | return ERR_PTR(-ENOMEM); | ||
986 | |||
987 | /* Get a client record */ | ||
988 | error = nfs4_set_client(server, hostname, addr, authflavour, | ||
989 | data->proto, data->timeo, data->retrans); | ||
990 | if (error < 0) | ||
991 | goto error; | ||
992 | |||
993 | /* set up the general RPC client */ | ||
994 | error = nfs4_init_server(server, data, authflavour); | ||
995 | if (error < 0) | ||
996 | goto error; | ||
997 | |||
998 | BUG_ON(!server->nfs_client); | ||
999 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1000 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1001 | |||
1002 | /* Probe the root fh to retrieve its FSID */ | ||
1003 | error = nfs4_path_walk(server, mntfh, mntpath); | ||
1004 | if (error < 0) | ||
1005 | goto error; | ||
1006 | |||
1007 | dprintk("Server FSID: %llx:%llx\n", | ||
1008 | (unsigned long long) server->fsid.major, | ||
1009 | (unsigned long long) server->fsid.minor); | ||
1010 | dprintk("Mount FH: %d\n", mntfh->size); | ||
1011 | |||
1012 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | ||
1013 | if (error < 0) | ||
1014 | goto error; | ||
1015 | |||
1016 | BUG_ON(!server->nfs_client); | ||
1017 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1018 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1019 | |||
1020 | spin_lock(&nfs_client_lock); | ||
1021 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1022 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1023 | spin_unlock(&nfs_client_lock); | ||
1024 | |||
1025 | server->mount_time = jiffies; | ||
1026 | dprintk("<-- nfs4_create_server() = %p\n", server); | ||
1027 | return server; | ||
1028 | |||
1029 | error: | ||
1030 | nfs_free_server(server); | ||
1031 | dprintk("<-- nfs4_create_server() = error %d\n", error); | ||
1032 | return ERR_PTR(error); | ||
1033 | } | ||
1034 | |||
1035 | /* | ||
1036 | * Create an NFS4 referral server record | ||
1037 | */ | ||
1038 | struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | ||
1039 | struct nfs_fh *fh) | ||
1040 | { | ||
1041 | struct nfs_client *parent_client; | ||
1042 | struct nfs_server *server, *parent_server; | ||
1043 | struct nfs_fattr fattr; | ||
1044 | int error; | ||
1045 | |||
1046 | dprintk("--> nfs4_create_referral_server()\n"); | ||
1047 | |||
1048 | server = nfs_alloc_server(); | ||
1049 | if (!server) | ||
1050 | return ERR_PTR(-ENOMEM); | ||
1051 | |||
1052 | parent_server = NFS_SB(data->sb); | ||
1053 | parent_client = parent_server->nfs_client; | ||
1054 | |||
1055 | /* Get a client representation. | ||
1056 | * Note: NFSv4 always uses TCP, */ | ||
1057 | error = nfs4_set_client(server, data->hostname, data->addr, | ||
1058 | data->authflavor, | ||
1059 | parent_server->client->cl_xprt->prot, | ||
1060 | parent_client->retrans_timeo, | ||
1061 | parent_client->retrans_count); | ||
1062 | if (error < 0) | ||
1063 | goto error; | ||
1064 | |||
1065 | /* Initialise the client representation from the parent server */ | ||
1066 | nfs_server_copy_userdata(server, parent_server); | ||
1067 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
1068 | |||
1069 | error = nfs_init_server_rpcclient(server, data->authflavor); | ||
1070 | if (error < 0) | ||
1071 | goto error; | ||
1072 | |||
1073 | BUG_ON(!server->nfs_client); | ||
1074 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1075 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1076 | |||
1077 | /* probe the filesystem info for this server filesystem */ | ||
1078 | error = nfs_probe_fsinfo(server, fh, &fattr); | ||
1079 | if (error < 0) | ||
1080 | goto error; | ||
1081 | |||
1082 | dprintk("Referral FSID: %llx:%llx\n", | ||
1083 | (unsigned long long) server->fsid.major, | ||
1084 | (unsigned long long) server->fsid.minor); | ||
1085 | |||
1086 | spin_lock(&nfs_client_lock); | ||
1087 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1088 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1089 | spin_unlock(&nfs_client_lock); | ||
1090 | |||
1091 | server->mount_time = jiffies; | ||
1092 | |||
1093 | dprintk("<-- nfs_create_referral_server() = %p\n", server); | ||
1094 | return server; | ||
1095 | |||
1096 | error: | ||
1097 | nfs_free_server(server); | ||
1098 | dprintk("<-- nfs4_create_referral_server() = error %d\n", error); | ||
1099 | return ERR_PTR(error); | ||
1100 | } | ||
1101 | |||
1102 | #endif /* CONFIG_NFS_V4 */ | ||
1103 | |||
1104 | /* | ||
1105 | * Clone an NFS2, NFS3 or NFS4 server record | ||
1106 | */ | ||
1107 | struct nfs_server *nfs_clone_server(struct nfs_server *source, | ||
1108 | struct nfs_fh *fh, | ||
1109 | struct nfs_fattr *fattr) | ||
1110 | { | ||
1111 | struct nfs_server *server; | ||
1112 | struct nfs_fattr fattr_fsinfo; | ||
1113 | int error; | ||
1114 | |||
1115 | dprintk("--> nfs_clone_server(,%llx:%llx,)\n", | ||
1116 | (unsigned long long) fattr->fsid.major, | ||
1117 | (unsigned long long) fattr->fsid.minor); | ||
1118 | |||
1119 | server = nfs_alloc_server(); | ||
1120 | if (!server) | ||
1121 | return ERR_PTR(-ENOMEM); | ||
1122 | |||
1123 | /* Copy data from the source */ | ||
1124 | server->nfs_client = source->nfs_client; | ||
1125 | atomic_inc(&server->nfs_client->cl_count); | ||
1126 | nfs_server_copy_userdata(server, source); | ||
1127 | |||
1128 | server->fsid = fattr->fsid; | ||
1129 | |||
1130 | error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor); | ||
1131 | if (error < 0) | ||
1132 | goto out_free_server; | ||
1133 | if (!IS_ERR(source->client_acl)) | ||
1134 | nfs_init_server_aclclient(server); | ||
1135 | |||
1136 | /* probe the filesystem info for this server filesystem */ | ||
1137 | error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo); | ||
1138 | if (error < 0) | ||
1139 | goto out_free_server; | ||
1140 | |||
1141 | dprintk("Cloned FSID: %llx:%llx\n", | ||
1142 | (unsigned long long) server->fsid.major, | ||
1143 | (unsigned long long) server->fsid.minor); | ||
1144 | |||
1145 | error = nfs_start_lockd(server); | ||
1146 | if (error < 0) | ||
1147 | goto out_free_server; | ||
1148 | |||
1149 | spin_lock(&nfs_client_lock); | ||
1150 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1151 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1152 | spin_unlock(&nfs_client_lock); | ||
1153 | |||
1154 | server->mount_time = jiffies; | ||
1155 | |||
1156 | dprintk("<-- nfs_clone_server() = %p\n", server); | ||
1157 | return server; | ||
1158 | |||
1159 | out_free_server: | ||
1160 | nfs_free_server(server); | ||
1161 | dprintk("<-- nfs_clone_server() = error %d\n", error); | ||
1162 | return ERR_PTR(error); | ||
1163 | } | ||
1164 | |||
1165 | #ifdef CONFIG_PROC_FS | ||
1166 | static struct proc_dir_entry *proc_fs_nfs; | ||
1167 | |||
1168 | static int nfs_server_list_open(struct inode *inode, struct file *file); | ||
1169 | static void *nfs_server_list_start(struct seq_file *p, loff_t *pos); | ||
1170 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos); | ||
1171 | static void nfs_server_list_stop(struct seq_file *p, void *v); | ||
1172 | static int nfs_server_list_show(struct seq_file *m, void *v); | ||
1173 | |||
1174 | static struct seq_operations nfs_server_list_ops = { | ||
1175 | .start = nfs_server_list_start, | ||
1176 | .next = nfs_server_list_next, | ||
1177 | .stop = nfs_server_list_stop, | ||
1178 | .show = nfs_server_list_show, | ||
1179 | }; | ||
1180 | |||
1181 | static struct file_operations nfs_server_list_fops = { | ||
1182 | .open = nfs_server_list_open, | ||
1183 | .read = seq_read, | ||
1184 | .llseek = seq_lseek, | ||
1185 | .release = seq_release, | ||
1186 | }; | ||
1187 | |||
1188 | static int nfs_volume_list_open(struct inode *inode, struct file *file); | ||
1189 | static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos); | ||
1190 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos); | ||
1191 | static void nfs_volume_list_stop(struct seq_file *p, void *v); | ||
1192 | static int nfs_volume_list_show(struct seq_file *m, void *v); | ||
1193 | |||
1194 | static struct seq_operations nfs_volume_list_ops = { | ||
1195 | .start = nfs_volume_list_start, | ||
1196 | .next = nfs_volume_list_next, | ||
1197 | .stop = nfs_volume_list_stop, | ||
1198 | .show = nfs_volume_list_show, | ||
1199 | }; | ||
1200 | |||
1201 | static struct file_operations nfs_volume_list_fops = { | ||
1202 | .open = nfs_volume_list_open, | ||
1203 | .read = seq_read, | ||
1204 | .llseek = seq_lseek, | ||
1205 | .release = seq_release, | ||
1206 | }; | ||
1207 | |||
1208 | /* | ||
1209 | * open "/proc/fs/nfsfs/servers" which provides a summary of servers with which | ||
1210 | * we're dealing | ||
1211 | */ | ||
1212 | static int nfs_server_list_open(struct inode *inode, struct file *file) | ||
1213 | { | ||
1214 | struct seq_file *m; | ||
1215 | int ret; | ||
1216 | |||
1217 | ret = seq_open(file, &nfs_server_list_ops); | ||
1218 | if (ret < 0) | ||
1219 | return ret; | ||
1220 | |||
1221 | m = file->private_data; | ||
1222 | m->private = PDE(inode)->data; | ||
1223 | |||
1224 | return 0; | ||
1225 | } | ||
1226 | |||
1227 | /* | ||
1228 | * set up the iterator to start reading from the server list and return the first item | ||
1229 | */ | ||
1230 | static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) | ||
1231 | { | ||
1232 | struct list_head *_p; | ||
1233 | loff_t pos = *_pos; | ||
1234 | |||
1235 | /* lock the list against modification */ | ||
1236 | spin_lock(&nfs_client_lock); | ||
1237 | |||
1238 | /* allow for the header line */ | ||
1239 | if (!pos) | ||
1240 | return SEQ_START_TOKEN; | ||
1241 | pos--; | ||
1242 | |||
1243 | /* find the n'th element in the list */ | ||
1244 | list_for_each(_p, &nfs_client_list) | ||
1245 | if (!pos--) | ||
1246 | break; | ||
1247 | |||
1248 | return _p != &nfs_client_list ? _p : NULL; | ||
1249 | } | ||
1250 | |||
1251 | /* | ||
1252 | * move to next server | ||
1253 | */ | ||
1254 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) | ||
1255 | { | ||
1256 | struct list_head *_p; | ||
1257 | |||
1258 | (*pos)++; | ||
1259 | |||
1260 | _p = v; | ||
1261 | _p = (v == SEQ_START_TOKEN) ? nfs_client_list.next : _p->next; | ||
1262 | |||
1263 | return _p != &nfs_client_list ? _p : NULL; | ||
1264 | } | ||
1265 | |||
1266 | /* | ||
1267 | * clean up after reading from the transports list | ||
1268 | */ | ||
1269 | static void nfs_server_list_stop(struct seq_file *p, void *v) | ||
1270 | { | ||
1271 | spin_unlock(&nfs_client_lock); | ||
1272 | } | ||
1273 | |||
1274 | /* | ||
1275 | * display a header line followed by a load of call lines | ||
1276 | */ | ||
1277 | static int nfs_server_list_show(struct seq_file *m, void *v) | ||
1278 | { | ||
1279 | struct nfs_client *clp; | ||
1280 | |||
1281 | /* display header on line 1 */ | ||
1282 | if (v == SEQ_START_TOKEN) { | ||
1283 | seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); | ||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | /* display one transport per line on subsequent lines */ | ||
1288 | clp = list_entry(v, struct nfs_client, cl_share_link); | ||
1289 | |||
1290 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n", | ||
1291 | clp->cl_nfsversion, | ||
1292 | NIPQUAD(clp->cl_addr.sin_addr), | ||
1293 | ntohs(clp->cl_addr.sin_port), | ||
1294 | atomic_read(&clp->cl_count), | ||
1295 | clp->cl_hostname); | ||
1296 | |||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | /* | ||
1301 | * open "/proc/fs/nfsfs/volumes" which provides a summary of extant volumes | ||
1302 | */ | ||
1303 | static int nfs_volume_list_open(struct inode *inode, struct file *file) | ||
1304 | { | ||
1305 | struct seq_file *m; | ||
1306 | int ret; | ||
1307 | |||
1308 | ret = seq_open(file, &nfs_volume_list_ops); | ||
1309 | if (ret < 0) | ||
1310 | return ret; | ||
1311 | |||
1312 | m = file->private_data; | ||
1313 | m->private = PDE(inode)->data; | ||
1314 | |||
1315 | return 0; | ||
1316 | } | ||
1317 | |||
1318 | /* | ||
1319 | * set up the iterator to start reading from the volume list and return the first item | ||
1320 | */ | ||
1321 | static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) | ||
1322 | { | ||
1323 | struct list_head *_p; | ||
1324 | loff_t pos = *_pos; | ||
1325 | |||
1326 | /* lock the list against modification */ | ||
1327 | spin_lock(&nfs_client_lock); | ||
1328 | |||
1329 | /* allow for the header line */ | ||
1330 | if (!pos) | ||
1331 | return SEQ_START_TOKEN; | ||
1332 | pos--; | ||
1333 | |||
1334 | /* find the n'th element in the list */ | ||
1335 | list_for_each(_p, &nfs_volume_list) | ||
1336 | if (!pos--) | ||
1337 | break; | ||
1338 | |||
1339 | return _p != &nfs_volume_list ? _p : NULL; | ||
1340 | } | ||
1341 | |||
1342 | /* | ||
1343 | * move to next volume | ||
1344 | */ | ||
1345 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) | ||
1346 | { | ||
1347 | struct list_head *_p; | ||
1348 | |||
1349 | (*pos)++; | ||
1350 | |||
1351 | _p = v; | ||
1352 | _p = (v == SEQ_START_TOKEN) ? nfs_volume_list.next : _p->next; | ||
1353 | |||
1354 | return _p != &nfs_volume_list ? _p : NULL; | ||
1355 | } | ||
1356 | |||
1357 | /* | ||
1358 | * clean up after reading from the transports list | ||
1359 | */ | ||
1360 | static void nfs_volume_list_stop(struct seq_file *p, void *v) | ||
1361 | { | ||
1362 | spin_unlock(&nfs_client_lock); | ||
1363 | } | ||
1364 | |||
1365 | /* | ||
1366 | * display a header line followed by a load of call lines | ||
1367 | */ | ||
1368 | static int nfs_volume_list_show(struct seq_file *m, void *v) | ||
1369 | { | ||
1370 | struct nfs_server *server; | ||
1371 | struct nfs_client *clp; | ||
1372 | char dev[8], fsid[17]; | ||
1373 | |||
1374 | /* display header on line 1 */ | ||
1375 | if (v == SEQ_START_TOKEN) { | ||
1376 | seq_puts(m, "NV SERVER PORT DEV FSID\n"); | ||
1377 | return 0; | ||
1378 | } | ||
1379 | /* display one transport per line on subsequent lines */ | ||
1380 | server = list_entry(v, struct nfs_server, master_link); | ||
1381 | clp = server->nfs_client; | ||
1382 | |||
1383 | snprintf(dev, 8, "%u:%u", | ||
1384 | MAJOR(server->s_dev), MINOR(server->s_dev)); | ||
1385 | |||
1386 | snprintf(fsid, 17, "%llx:%llx", | ||
1387 | (unsigned long long) server->fsid.major, | ||
1388 | (unsigned long long) server->fsid.minor); | ||
1389 | |||
1390 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n", | ||
1391 | clp->cl_nfsversion, | ||
1392 | NIPQUAD(clp->cl_addr.sin_addr), | ||
1393 | ntohs(clp->cl_addr.sin_port), | ||
1394 | dev, | ||
1395 | fsid); | ||
1396 | |||
1397 | return 0; | ||
1398 | } | ||
1399 | |||
1400 | /* | ||
1401 | * initialise the /proc/fs/nfsfs/ directory | ||
1402 | */ | ||
1403 | int __init nfs_fs_proc_init(void) | ||
1404 | { | ||
1405 | struct proc_dir_entry *p; | ||
1406 | |||
1407 | proc_fs_nfs = proc_mkdir("nfsfs", proc_root_fs); | ||
1408 | if (!proc_fs_nfs) | ||
1409 | goto error_0; | ||
1410 | |||
1411 | proc_fs_nfs->owner = THIS_MODULE; | ||
1412 | |||
1413 | /* a file of servers with which we're dealing */ | ||
1414 | p = create_proc_entry("servers", S_IFREG|S_IRUGO, proc_fs_nfs); | ||
1415 | if (!p) | ||
1416 | goto error_1; | ||
1417 | |||
1418 | p->proc_fops = &nfs_server_list_fops; | ||
1419 | p->owner = THIS_MODULE; | ||
1420 | |||
1421 | /* a file of volumes that we have mounted */ | ||
1422 | p = create_proc_entry("volumes", S_IFREG|S_IRUGO, proc_fs_nfs); | ||
1423 | if (!p) | ||
1424 | goto error_2; | ||
1425 | |||
1426 | p->proc_fops = &nfs_volume_list_fops; | ||
1427 | p->owner = THIS_MODULE; | ||
1428 | return 0; | ||
1429 | |||
1430 | error_2: | ||
1431 | remove_proc_entry("servers", proc_fs_nfs); | ||
1432 | error_1: | ||
1433 | remove_proc_entry("nfsfs", proc_root_fs); | ||
1434 | error_0: | ||
1435 | return -ENOMEM; | ||
1436 | } | ||
1437 | |||
1438 | /* | ||
1439 | * clean up the /proc/fs/nfsfs/ directory | ||
1440 | */ | ||
1441 | void nfs_fs_proc_exit(void) | ||
1442 | { | ||
1443 | remove_proc_entry("volumes", proc_fs_nfs); | ||
1444 | remove_proc_entry("servers", proc_fs_nfs); | ||
1445 | remove_proc_entry("nfsfs", proc_root_fs); | ||
1446 | } | ||
1447 | |||
1448 | #endif /* CONFIG_PROC_FS */ | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 9540a316c05e..57133678db16 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include "nfs4_fs.h" | 19 | #include "nfs4_fs.h" |
20 | #include "delegation.h" | 20 | #include "delegation.h" |
21 | #include "internal.h" | ||
21 | 22 | ||
22 | static struct nfs_delegation *nfs_alloc_delegation(void) | 23 | static struct nfs_delegation *nfs_alloc_delegation(void) |
23 | { | 24 | { |
@@ -52,7 +53,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
52 | case -NFS4ERR_EXPIRED: | 53 | case -NFS4ERR_EXPIRED: |
53 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | 54 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
54 | case -NFS4ERR_STALE_CLIENTID: | 55 | case -NFS4ERR_STALE_CLIENTID: |
55 | nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs4_state); | 56 | nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client); |
56 | goto out_err; | 57 | goto out_err; |
57 | } | 58 | } |
58 | } | 59 | } |
@@ -114,7 +115,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st | |||
114 | */ | 115 | */ |
115 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) | 116 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) |
116 | { | 117 | { |
117 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | 118 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
118 | struct nfs_inode *nfsi = NFS_I(inode); | 119 | struct nfs_inode *nfsi = NFS_I(inode); |
119 | struct nfs_delegation *delegation; | 120 | struct nfs_delegation *delegation; |
120 | int status = 0; | 121 | int status = 0; |
@@ -145,7 +146,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
145 | sizeof(delegation->stateid)) != 0 || | 146 | sizeof(delegation->stateid)) != 0 || |
146 | delegation->type != nfsi->delegation->type) { | 147 | delegation->type != nfsi->delegation->type) { |
147 | printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", | 148 | printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", |
148 | __FUNCTION__, NIPQUAD(clp->cl_addr)); | 149 | __FUNCTION__, NIPQUAD(clp->cl_addr.sin_addr)); |
149 | status = -EIO; | 150 | status = -EIO; |
150 | } | 151 | } |
151 | } | 152 | } |
@@ -176,7 +177,7 @@ static void nfs_msync_inode(struct inode *inode) | |||
176 | */ | 177 | */ |
177 | int __nfs_inode_return_delegation(struct inode *inode) | 178 | int __nfs_inode_return_delegation(struct inode *inode) |
178 | { | 179 | { |
179 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | 180 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
180 | struct nfs_inode *nfsi = NFS_I(inode); | 181 | struct nfs_inode *nfsi = NFS_I(inode); |
181 | struct nfs_delegation *delegation; | 182 | struct nfs_delegation *delegation; |
182 | int res = 0; | 183 | int res = 0; |
@@ -208,7 +209,7 @@ int __nfs_inode_return_delegation(struct inode *inode) | |||
208 | */ | 209 | */ |
209 | void nfs_return_all_delegations(struct super_block *sb) | 210 | void nfs_return_all_delegations(struct super_block *sb) |
210 | { | 211 | { |
211 | struct nfs4_client *clp = NFS_SB(sb)->nfs4_state; | 212 | struct nfs_client *clp = NFS_SB(sb)->nfs_client; |
212 | struct nfs_delegation *delegation; | 213 | struct nfs_delegation *delegation; |
213 | struct inode *inode; | 214 | struct inode *inode; |
214 | 215 | ||
@@ -232,7 +233,7 @@ restart: | |||
232 | 233 | ||
233 | int nfs_do_expire_all_delegations(void *ptr) | 234 | int nfs_do_expire_all_delegations(void *ptr) |
234 | { | 235 | { |
235 | struct nfs4_client *clp = ptr; | 236 | struct nfs_client *clp = ptr; |
236 | struct nfs_delegation *delegation; | 237 | struct nfs_delegation *delegation; |
237 | struct inode *inode; | 238 | struct inode *inode; |
238 | 239 | ||
@@ -254,11 +255,11 @@ restart: | |||
254 | } | 255 | } |
255 | out: | 256 | out: |
256 | spin_unlock(&clp->cl_lock); | 257 | spin_unlock(&clp->cl_lock); |
257 | nfs4_put_client(clp); | 258 | nfs_put_client(clp); |
258 | module_put_and_exit(0); | 259 | module_put_and_exit(0); |
259 | } | 260 | } |
260 | 261 | ||
261 | void nfs_expire_all_delegations(struct nfs4_client *clp) | 262 | void nfs_expire_all_delegations(struct nfs_client *clp) |
262 | { | 263 | { |
263 | struct task_struct *task; | 264 | struct task_struct *task; |
264 | 265 | ||
@@ -266,17 +267,17 @@ void nfs_expire_all_delegations(struct nfs4_client *clp) | |||
266 | atomic_inc(&clp->cl_count); | 267 | atomic_inc(&clp->cl_count); |
267 | task = kthread_run(nfs_do_expire_all_delegations, clp, | 268 | task = kthread_run(nfs_do_expire_all_delegations, clp, |
268 | "%u.%u.%u.%u-delegreturn", | 269 | "%u.%u.%u.%u-delegreturn", |
269 | NIPQUAD(clp->cl_addr)); | 270 | NIPQUAD(clp->cl_addr.sin_addr)); |
270 | if (!IS_ERR(task)) | 271 | if (!IS_ERR(task)) |
271 | return; | 272 | return; |
272 | nfs4_put_client(clp); | 273 | nfs_put_client(clp); |
273 | module_put(THIS_MODULE); | 274 | module_put(THIS_MODULE); |
274 | } | 275 | } |
275 | 276 | ||
276 | /* | 277 | /* |
277 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. | 278 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. |
278 | */ | 279 | */ |
279 | void nfs_handle_cb_pathdown(struct nfs4_client *clp) | 280 | void nfs_handle_cb_pathdown(struct nfs_client *clp) |
280 | { | 281 | { |
281 | struct nfs_delegation *delegation; | 282 | struct nfs_delegation *delegation; |
282 | struct inode *inode; | 283 | struct inode *inode; |
@@ -299,7 +300,7 @@ restart: | |||
299 | 300 | ||
300 | struct recall_threadargs { | 301 | struct recall_threadargs { |
301 | struct inode *inode; | 302 | struct inode *inode; |
302 | struct nfs4_client *clp; | 303 | struct nfs_client *clp; |
303 | const nfs4_stateid *stateid; | 304 | const nfs4_stateid *stateid; |
304 | 305 | ||
305 | struct completion started; | 306 | struct completion started; |
@@ -310,7 +311,7 @@ static int recall_thread(void *data) | |||
310 | { | 311 | { |
311 | struct recall_threadargs *args = (struct recall_threadargs *)data; | 312 | struct recall_threadargs *args = (struct recall_threadargs *)data; |
312 | struct inode *inode = igrab(args->inode); | 313 | struct inode *inode = igrab(args->inode); |
313 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | 314 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
314 | struct nfs_inode *nfsi = NFS_I(inode); | 315 | struct nfs_inode *nfsi = NFS_I(inode); |
315 | struct nfs_delegation *delegation; | 316 | struct nfs_delegation *delegation; |
316 | 317 | ||
@@ -371,7 +372,7 @@ out_module_put: | |||
371 | /* | 372 | /* |
372 | * Retrieve the inode associated with a delegation | 373 | * Retrieve the inode associated with a delegation |
373 | */ | 374 | */ |
374 | struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle) | 375 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle) |
375 | { | 376 | { |
376 | struct nfs_delegation *delegation; | 377 | struct nfs_delegation *delegation; |
377 | struct inode *res = NULL; | 378 | struct inode *res = NULL; |
@@ -389,7 +390,7 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf | |||
389 | /* | 390 | /* |
390 | * Mark all delegations as needing to be reclaimed | 391 | * Mark all delegations as needing to be reclaimed |
391 | */ | 392 | */ |
392 | void nfs_delegation_mark_reclaim(struct nfs4_client *clp) | 393 | void nfs_delegation_mark_reclaim(struct nfs_client *clp) |
393 | { | 394 | { |
394 | struct nfs_delegation *delegation; | 395 | struct nfs_delegation *delegation; |
395 | spin_lock(&clp->cl_lock); | 396 | spin_lock(&clp->cl_lock); |
@@ -401,7 +402,7 @@ void nfs_delegation_mark_reclaim(struct nfs4_client *clp) | |||
401 | /* | 402 | /* |
402 | * Reap all unclaimed delegations after reboot recovery is done | 403 | * Reap all unclaimed delegations after reboot recovery is done |
403 | */ | 404 | */ |
404 | void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) | 405 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp) |
405 | { | 406 | { |
406 | struct nfs_delegation *delegation, *n; | 407 | struct nfs_delegation *delegation, *n; |
407 | LIST_HEAD(head); | 408 | LIST_HEAD(head); |
@@ -423,7 +424,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) | |||
423 | 424 | ||
424 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) | 425 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) |
425 | { | 426 | { |
426 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | 427 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
427 | struct nfs_inode *nfsi = NFS_I(inode); | 428 | struct nfs_inode *nfsi = NFS_I(inode); |
428 | struct nfs_delegation *delegation; | 429 | struct nfs_delegation *delegation; |
429 | int res = 0; | 430 | int res = 0; |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 3858694652fa..2cfd4b24c7fe 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -29,13 +29,13 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st | |||
29 | int __nfs_inode_return_delegation(struct inode *inode); | 29 | int __nfs_inode_return_delegation(struct inode *inode); |
30 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | 30 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); |
31 | 31 | ||
32 | struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); | 32 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
33 | void nfs_return_all_delegations(struct super_block *sb); | 33 | void nfs_return_all_delegations(struct super_block *sb); |
34 | void nfs_expire_all_delegations(struct nfs4_client *clp); | 34 | void nfs_expire_all_delegations(struct nfs_client *clp); |
35 | void nfs_handle_cb_pathdown(struct nfs4_client *clp); | 35 | void nfs_handle_cb_pathdown(struct nfs_client *clp); |
36 | 36 | ||
37 | void nfs_delegation_mark_reclaim(struct nfs4_client *clp); | 37 | void nfs_delegation_mark_reclaim(struct nfs_client *clp); |
38 | void nfs_delegation_reap_unclaimed(struct nfs4_client *clp); | 38 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); |
39 | 39 | ||
40 | /* NFSv4 delegation-related procedures */ | 40 | /* NFSv4 delegation-related procedures */ |
41 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); | 41 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e7ffb4deb3e5..3419c2da9ba9 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -30,7 +30,9 @@ | |||
30 | #include <linux/nfs_mount.h> | 30 | #include <linux/nfs_mount.h> |
31 | #include <linux/pagemap.h> | 31 | #include <linux/pagemap.h> |
32 | #include <linux/smp_lock.h> | 32 | #include <linux/smp_lock.h> |
33 | #include <linux/pagevec.h> | ||
33 | #include <linux/namei.h> | 34 | #include <linux/namei.h> |
35 | #include <linux/mount.h> | ||
34 | 36 | ||
35 | #include "nfs4_fs.h" | 37 | #include "nfs4_fs.h" |
36 | #include "delegation.h" | 38 | #include "delegation.h" |
@@ -870,14 +872,14 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) | |||
870 | return (nd->intent.open.flags & O_EXCL) != 0; | 872 | return (nd->intent.open.flags & O_EXCL) != 0; |
871 | } | 873 | } |
872 | 874 | ||
873 | static inline int nfs_reval_fsid(struct inode *dir, | 875 | static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir, |
874 | struct nfs_fh *fh, struct nfs_fattr *fattr) | 876 | struct nfs_fh *fh, struct nfs_fattr *fattr) |
875 | { | 877 | { |
876 | struct nfs_server *server = NFS_SERVER(dir); | 878 | struct nfs_server *server = NFS_SERVER(dir); |
877 | 879 | ||
878 | if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) | 880 | if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) |
879 | /* Revalidate fsid on root dir */ | 881 | /* Revalidate fsid on root dir */ |
880 | return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode); | 882 | return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode); |
881 | return 0; | 883 | return 0; |
882 | } | 884 | } |
883 | 885 | ||
@@ -902,9 +904,15 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
902 | 904 | ||
903 | lock_kernel(); | 905 | lock_kernel(); |
904 | 906 | ||
905 | /* If we're doing an exclusive create, optimize away the lookup */ | 907 | /* |
906 | if (nfs_is_exclusive_create(dir, nd)) | 908 | * If we're doing an exclusive create, optimize away the lookup |
907 | goto no_entry; | 909 | * but don't hash the dentry. |
910 | */ | ||
911 | if (nfs_is_exclusive_create(dir, nd)) { | ||
912 | d_instantiate(dentry, NULL); | ||
913 | res = NULL; | ||
914 | goto out_unlock; | ||
915 | } | ||
908 | 916 | ||
909 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 917 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); |
910 | if (error == -ENOENT) | 918 | if (error == -ENOENT) |
@@ -913,7 +921,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
913 | res = ERR_PTR(error); | 921 | res = ERR_PTR(error); |
914 | goto out_unlock; | 922 | goto out_unlock; |
915 | } | 923 | } |
916 | error = nfs_reval_fsid(dir, &fhandle, &fattr); | 924 | error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr); |
917 | if (error < 0) { | 925 | if (error < 0) { |
918 | res = ERR_PTR(error); | 926 | res = ERR_PTR(error); |
919 | goto out_unlock; | 927 | goto out_unlock; |
@@ -922,8 +930,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
922 | res = (struct dentry *)inode; | 930 | res = (struct dentry *)inode; |
923 | if (IS_ERR(res)) | 931 | if (IS_ERR(res)) |
924 | goto out_unlock; | 932 | goto out_unlock; |
933 | |||
925 | no_entry: | 934 | no_entry: |
926 | res = d_add_unique(dentry, inode); | 935 | res = d_materialise_unique(dentry, inode); |
927 | if (res != NULL) | 936 | if (res != NULL) |
928 | dentry = res; | 937 | dentry = res; |
929 | nfs_renew_times(dentry); | 938 | nfs_renew_times(dentry); |
@@ -1117,11 +1126,13 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) | |||
1117 | dput(dentry); | 1126 | dput(dentry); |
1118 | return NULL; | 1127 | return NULL; |
1119 | } | 1128 | } |
1120 | alias = d_add_unique(dentry, inode); | 1129 | |
1130 | alias = d_materialise_unique(dentry, inode); | ||
1121 | if (alias != NULL) { | 1131 | if (alias != NULL) { |
1122 | dput(dentry); | 1132 | dput(dentry); |
1123 | dentry = alias; | 1133 | dentry = alias; |
1124 | } | 1134 | } |
1135 | |||
1125 | nfs_renew_times(dentry); | 1136 | nfs_renew_times(dentry); |
1126 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1137 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1127 | return dentry; | 1138 | return dentry; |
@@ -1143,23 +1154,22 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | |||
1143 | struct inode *dir = dentry->d_parent->d_inode; | 1154 | struct inode *dir = dentry->d_parent->d_inode; |
1144 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1155 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
1145 | if (error) | 1156 | if (error) |
1146 | goto out_err; | 1157 | return error; |
1147 | } | 1158 | } |
1148 | if (!(fattr->valid & NFS_ATTR_FATTR)) { | 1159 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
1149 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 1160 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
1150 | error = server->rpc_ops->getattr(server, fhandle, fattr); | 1161 | error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); |
1151 | if (error < 0) | 1162 | if (error < 0) |
1152 | goto out_err; | 1163 | return error; |
1153 | } | 1164 | } |
1154 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); | 1165 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
1155 | error = PTR_ERR(inode); | 1166 | error = PTR_ERR(inode); |
1156 | if (IS_ERR(inode)) | 1167 | if (IS_ERR(inode)) |
1157 | goto out_err; | 1168 | return error; |
1158 | d_instantiate(dentry, inode); | 1169 | d_instantiate(dentry, inode); |
1170 | if (d_unhashed(dentry)) | ||
1171 | d_rehash(dentry); | ||
1159 | return 0; | 1172 | return 0; |
1160 | out_err: | ||
1161 | d_drop(dentry); | ||
1162 | return error; | ||
1163 | } | 1173 | } |
1164 | 1174 | ||
1165 | /* | 1175 | /* |
@@ -1440,48 +1450,82 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1440 | return error; | 1450 | return error; |
1441 | } | 1451 | } |
1442 | 1452 | ||
1443 | static int | 1453 | /* |
1444 | nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 1454 | * To create a symbolic link, most file systems instantiate a new inode, |
1455 | * add a page to it containing the path, then write it out to the disk | ||
1456 | * using prepare_write/commit_write. | ||
1457 | * | ||
1458 | * Unfortunately the NFS client can't create the in-core inode first | ||
1459 | * because it needs a file handle to create an in-core inode (see | ||
1460 | * fs/nfs/inode.c:nfs_fhget). We only have a file handle *after* the | ||
1461 | * symlink request has completed on the server. | ||
1462 | * | ||
1463 | * So instead we allocate a raw page, copy the symname into it, then do | ||
1464 | * the SYMLINK request with the page as the buffer. If it succeeds, we | ||
1465 | * now have a new file handle and can instantiate an in-core NFS inode | ||
1466 | * and move the raw page into its mapping. | ||
1467 | */ | ||
1468 | static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | ||
1445 | { | 1469 | { |
1470 | struct pagevec lru_pvec; | ||
1471 | struct page *page; | ||
1472 | char *kaddr; | ||
1446 | struct iattr attr; | 1473 | struct iattr attr; |
1447 | struct nfs_fattr sym_attr; | 1474 | unsigned int pathlen = strlen(symname); |
1448 | struct nfs_fh sym_fh; | ||
1449 | struct qstr qsymname; | ||
1450 | int error; | 1475 | int error; |
1451 | 1476 | ||
1452 | dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, | 1477 | dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, |
1453 | dir->i_ino, dentry->d_name.name, symname); | 1478 | dir->i_ino, dentry->d_name.name, symname); |
1454 | 1479 | ||
1455 | #ifdef NFS_PARANOIA | 1480 | if (pathlen > PAGE_SIZE) |
1456 | if (dentry->d_inode) | 1481 | return -ENAMETOOLONG; |
1457 | printk("nfs_proc_symlink: %s/%s not negative!\n", | ||
1458 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
1459 | #endif | ||
1460 | /* | ||
1461 | * Fill in the sattr for the call. | ||
1462 | * Note: SunOS 4.1.2 crashes if the mode isn't initialized! | ||
1463 | */ | ||
1464 | attr.ia_valid = ATTR_MODE; | ||
1465 | attr.ia_mode = S_IFLNK | S_IRWXUGO; | ||
1466 | 1482 | ||
1467 | qsymname.name = symname; | 1483 | attr.ia_mode = S_IFLNK | S_IRWXUGO; |
1468 | qsymname.len = strlen(symname); | 1484 | attr.ia_valid = ATTR_MODE; |
1469 | 1485 | ||
1470 | lock_kernel(); | 1486 | lock_kernel(); |
1487 | |||
1488 | page = alloc_page(GFP_KERNEL); | ||
1489 | if (!page) { | ||
1490 | unlock_kernel(); | ||
1491 | return -ENOMEM; | ||
1492 | } | ||
1493 | |||
1494 | kaddr = kmap_atomic(page, KM_USER0); | ||
1495 | memcpy(kaddr, symname, pathlen); | ||
1496 | if (pathlen < PAGE_SIZE) | ||
1497 | memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); | ||
1498 | kunmap_atomic(kaddr, KM_USER0); | ||
1499 | |||
1471 | nfs_begin_data_update(dir); | 1500 | nfs_begin_data_update(dir); |
1472 | error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname, | 1501 | error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); |
1473 | &attr, &sym_fh, &sym_attr); | ||
1474 | nfs_end_data_update(dir); | 1502 | nfs_end_data_update(dir); |
1475 | if (!error) { | 1503 | if (error != 0) { |
1476 | error = nfs_instantiate(dentry, &sym_fh, &sym_attr); | 1504 | dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n", |
1477 | } else { | 1505 | dir->i_sb->s_id, dir->i_ino, |
1478 | if (error == -EEXIST) | 1506 | dentry->d_name.name, symname, error); |
1479 | printk("nfs_proc_symlink: %s/%s already exists??\n", | ||
1480 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
1481 | d_drop(dentry); | 1507 | d_drop(dentry); |
1508 | __free_page(page); | ||
1509 | unlock_kernel(); | ||
1510 | return error; | ||
1482 | } | 1511 | } |
1512 | |||
1513 | /* | ||
1514 | * No big deal if we can't add this page to the page cache here. | ||
1515 | * READLINK will get the missing page from the server if needed. | ||
1516 | */ | ||
1517 | pagevec_init(&lru_pvec, 0); | ||
1518 | if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0, | ||
1519 | GFP_KERNEL)) { | ||
1520 | if (!pagevec_add(&lru_pvec, page)) | ||
1521 | __pagevec_lru_add(&lru_pvec); | ||
1522 | SetPageUptodate(page); | ||
1523 | unlock_page(page); | ||
1524 | } else | ||
1525 | __free_page(page); | ||
1526 | |||
1483 | unlock_kernel(); | 1527 | unlock_kernel(); |
1484 | return error; | 1528 | return 0; |
1485 | } | 1529 | } |
1486 | 1530 | ||
1487 | static int | 1531 | static int |
@@ -1638,35 +1682,211 @@ out: | |||
1638 | return error; | 1682 | return error; |
1639 | } | 1683 | } |
1640 | 1684 | ||
1685 | static DEFINE_SPINLOCK(nfs_access_lru_lock); | ||
1686 | static LIST_HEAD(nfs_access_lru_list); | ||
1687 | static atomic_long_t nfs_access_nr_entries; | ||
1688 | |||
1689 | static void nfs_access_free_entry(struct nfs_access_entry *entry) | ||
1690 | { | ||
1691 | put_rpccred(entry->cred); | ||
1692 | kfree(entry); | ||
1693 | smp_mb__before_atomic_dec(); | ||
1694 | atomic_long_dec(&nfs_access_nr_entries); | ||
1695 | smp_mb__after_atomic_dec(); | ||
1696 | } | ||
1697 | |||
1698 | int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | ||
1699 | { | ||
1700 | LIST_HEAD(head); | ||
1701 | struct nfs_inode *nfsi; | ||
1702 | struct nfs_access_entry *cache; | ||
1703 | |||
1704 | spin_lock(&nfs_access_lru_lock); | ||
1705 | restart: | ||
1706 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | ||
1707 | struct inode *inode; | ||
1708 | |||
1709 | if (nr_to_scan-- == 0) | ||
1710 | break; | ||
1711 | inode = igrab(&nfsi->vfs_inode); | ||
1712 | if (inode == NULL) | ||
1713 | continue; | ||
1714 | spin_lock(&inode->i_lock); | ||
1715 | if (list_empty(&nfsi->access_cache_entry_lru)) | ||
1716 | goto remove_lru_entry; | ||
1717 | cache = list_entry(nfsi->access_cache_entry_lru.next, | ||
1718 | struct nfs_access_entry, lru); | ||
1719 | list_move(&cache->lru, &head); | ||
1720 | rb_erase(&cache->rb_node, &nfsi->access_cache); | ||
1721 | if (!list_empty(&nfsi->access_cache_entry_lru)) | ||
1722 | list_move_tail(&nfsi->access_cache_inode_lru, | ||
1723 | &nfs_access_lru_list); | ||
1724 | else { | ||
1725 | remove_lru_entry: | ||
1726 | list_del_init(&nfsi->access_cache_inode_lru); | ||
1727 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); | ||
1728 | } | ||
1729 | spin_unlock(&inode->i_lock); | ||
1730 | iput(inode); | ||
1731 | goto restart; | ||
1732 | } | ||
1733 | spin_unlock(&nfs_access_lru_lock); | ||
1734 | while (!list_empty(&head)) { | ||
1735 | cache = list_entry(head.next, struct nfs_access_entry, lru); | ||
1736 | list_del(&cache->lru); | ||
1737 | nfs_access_free_entry(cache); | ||
1738 | } | ||
1739 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; | ||
1740 | } | ||
1741 | |||
1742 | static void __nfs_access_zap_cache(struct inode *inode) | ||
1743 | { | ||
1744 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1745 | struct rb_root *root_node = &nfsi->access_cache; | ||
1746 | struct rb_node *n, *dispose = NULL; | ||
1747 | struct nfs_access_entry *entry; | ||
1748 | |||
1749 | /* Unhook entries from the cache */ | ||
1750 | while ((n = rb_first(root_node)) != NULL) { | ||
1751 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | ||
1752 | rb_erase(n, root_node); | ||
1753 | list_del(&entry->lru); | ||
1754 | n->rb_left = dispose; | ||
1755 | dispose = n; | ||
1756 | } | ||
1757 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | ||
1758 | spin_unlock(&inode->i_lock); | ||
1759 | |||
1760 | /* Now kill them all! */ | ||
1761 | while (dispose != NULL) { | ||
1762 | n = dispose; | ||
1763 | dispose = n->rb_left; | ||
1764 | nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node)); | ||
1765 | } | ||
1766 | } | ||
1767 | |||
1768 | void nfs_access_zap_cache(struct inode *inode) | ||
1769 | { | ||
1770 | /* Remove from global LRU init */ | ||
1771 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) { | ||
1772 | spin_lock(&nfs_access_lru_lock); | ||
1773 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); | ||
1774 | spin_unlock(&nfs_access_lru_lock); | ||
1775 | } | ||
1776 | |||
1777 | spin_lock(&inode->i_lock); | ||
1778 | /* This will release the spinlock */ | ||
1779 | __nfs_access_zap_cache(inode); | ||
1780 | } | ||
1781 | |||
1782 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) | ||
1783 | { | ||
1784 | struct rb_node *n = NFS_I(inode)->access_cache.rb_node; | ||
1785 | struct nfs_access_entry *entry; | ||
1786 | |||
1787 | while (n != NULL) { | ||
1788 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | ||
1789 | |||
1790 | if (cred < entry->cred) | ||
1791 | n = n->rb_left; | ||
1792 | else if (cred > entry->cred) | ||
1793 | n = n->rb_right; | ||
1794 | else | ||
1795 | return entry; | ||
1796 | } | ||
1797 | return NULL; | ||
1798 | } | ||
1799 | |||
1641 | int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) | 1800 | int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) |
1642 | { | 1801 | { |
1643 | struct nfs_inode *nfsi = NFS_I(inode); | 1802 | struct nfs_inode *nfsi = NFS_I(inode); |
1644 | struct nfs_access_entry *cache = &nfsi->cache_access; | 1803 | struct nfs_access_entry *cache; |
1804 | int err = -ENOENT; | ||
1645 | 1805 | ||
1646 | if (cache->cred != cred | 1806 | spin_lock(&inode->i_lock); |
1647 | || time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) | 1807 | if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS) |
1648 | || (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)) | 1808 | goto out_zap; |
1649 | return -ENOENT; | 1809 | cache = nfs_access_search_rbtree(inode, cred); |
1650 | memcpy(res, cache, sizeof(*res)); | 1810 | if (cache == NULL) |
1651 | return 0; | 1811 | goto out; |
1812 | if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) | ||
1813 | goto out_stale; | ||
1814 | res->jiffies = cache->jiffies; | ||
1815 | res->cred = cache->cred; | ||
1816 | res->mask = cache->mask; | ||
1817 | list_move_tail(&cache->lru, &nfsi->access_cache_entry_lru); | ||
1818 | err = 0; | ||
1819 | out: | ||
1820 | spin_unlock(&inode->i_lock); | ||
1821 | return err; | ||
1822 | out_stale: | ||
1823 | rb_erase(&cache->rb_node, &nfsi->access_cache); | ||
1824 | list_del(&cache->lru); | ||
1825 | spin_unlock(&inode->i_lock); | ||
1826 | nfs_access_free_entry(cache); | ||
1827 | return -ENOENT; | ||
1828 | out_zap: | ||
1829 | /* This will release the spinlock */ | ||
1830 | __nfs_access_zap_cache(inode); | ||
1831 | return -ENOENT; | ||
1652 | } | 1832 | } |
1653 | 1833 | ||
1654 | void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | 1834 | static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set) |
1655 | { | 1835 | { |
1656 | struct nfs_inode *nfsi = NFS_I(inode); | 1836 | struct nfs_inode *nfsi = NFS_I(inode); |
1657 | struct nfs_access_entry *cache = &nfsi->cache_access; | 1837 | struct rb_root *root_node = &nfsi->access_cache; |
1838 | struct rb_node **p = &root_node->rb_node; | ||
1839 | struct rb_node *parent = NULL; | ||
1840 | struct nfs_access_entry *entry; | ||
1658 | 1841 | ||
1659 | if (cache->cred != set->cred) { | ||
1660 | if (cache->cred) | ||
1661 | put_rpccred(cache->cred); | ||
1662 | cache->cred = get_rpccred(set->cred); | ||
1663 | } | ||
1664 | /* FIXME: replace current access_cache BKL reliance with inode->i_lock */ | ||
1665 | spin_lock(&inode->i_lock); | 1842 | spin_lock(&inode->i_lock); |
1666 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | 1843 | while (*p != NULL) { |
1844 | parent = *p; | ||
1845 | entry = rb_entry(parent, struct nfs_access_entry, rb_node); | ||
1846 | |||
1847 | if (set->cred < entry->cred) | ||
1848 | p = &parent->rb_left; | ||
1849 | else if (set->cred > entry->cred) | ||
1850 | p = &parent->rb_right; | ||
1851 | else | ||
1852 | goto found; | ||
1853 | } | ||
1854 | rb_link_node(&set->rb_node, parent, p); | ||
1855 | rb_insert_color(&set->rb_node, root_node); | ||
1856 | list_add_tail(&set->lru, &nfsi->access_cache_entry_lru); | ||
1667 | spin_unlock(&inode->i_lock); | 1857 | spin_unlock(&inode->i_lock); |
1858 | return; | ||
1859 | found: | ||
1860 | rb_replace_node(parent, &set->rb_node, root_node); | ||
1861 | list_add_tail(&set->lru, &nfsi->access_cache_entry_lru); | ||
1862 | list_del(&entry->lru); | ||
1863 | spin_unlock(&inode->i_lock); | ||
1864 | nfs_access_free_entry(entry); | ||
1865 | } | ||
1866 | |||
1867 | void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | ||
1868 | { | ||
1869 | struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL); | ||
1870 | if (cache == NULL) | ||
1871 | return; | ||
1872 | RB_CLEAR_NODE(&cache->rb_node); | ||
1668 | cache->jiffies = set->jiffies; | 1873 | cache->jiffies = set->jiffies; |
1874 | cache->cred = get_rpccred(set->cred); | ||
1669 | cache->mask = set->mask; | 1875 | cache->mask = set->mask; |
1876 | |||
1877 | nfs_access_add_rbtree(inode, cache); | ||
1878 | |||
1879 | /* Update accounting */ | ||
1880 | smp_mb__before_atomic_inc(); | ||
1881 | atomic_long_inc(&nfs_access_nr_entries); | ||
1882 | smp_mb__after_atomic_inc(); | ||
1883 | |||
1884 | /* Add inode to global LRU list */ | ||
1885 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) { | ||
1886 | spin_lock(&nfs_access_lru_lock); | ||
1887 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); | ||
1888 | spin_unlock(&nfs_access_lru_lock); | ||
1889 | } | ||
1670 | } | 1890 | } |
1671 | 1891 | ||
1672 | static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) | 1892 | static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 48e892880d5b..be997d649127 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -111,7 +111,7 @@ nfs_file_open(struct inode *inode, struct file *filp) | |||
111 | 111 | ||
112 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); | 112 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); |
113 | lock_kernel(); | 113 | lock_kernel(); |
114 | res = NFS_SERVER(inode)->rpc_ops->file_open(inode, filp); | 114 | res = NFS_PROTO(inode)->file_open(inode, filp); |
115 | unlock_kernel(); | 115 | unlock_kernel(); |
116 | return res; | 116 | return res; |
117 | } | 117 | } |
@@ -157,7 +157,7 @@ force_reval: | |||
157 | static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | 157 | static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) |
158 | { | 158 | { |
159 | /* origin == SEEK_END => we must revalidate the cached file length */ | 159 | /* origin == SEEK_END => we must revalidate the cached file length */ |
160 | if (origin == 2) { | 160 | if (origin == SEEK_END) { |
161 | struct inode *inode = filp->f_mapping->host; | 161 | struct inode *inode = filp->f_mapping->host; |
162 | int retval = nfs_revalidate_file_size(inode, filp); | 162 | int retval = nfs_revalidate_file_size(inode, filp); |
163 | if (retval < 0) | 163 | if (retval < 0) |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c new file mode 100644 index 000000000000..76b08ae9ed82 --- /dev/null +++ b/fs/nfs/getroot.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /* getroot.c: get the root dentry for an NFS mount | ||
2 | * | ||
3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | |||
16 | #include <linux/time.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/stat.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/sunrpc/clnt.h> | ||
24 | #include <linux/sunrpc/stats.h> | ||
25 | #include <linux/nfs_fs.h> | ||
26 | #include <linux/nfs_mount.h> | ||
27 | #include <linux/nfs4_mount.h> | ||
28 | #include <linux/lockd/bind.h> | ||
29 | #include <linux/smp_lock.h> | ||
30 | #include <linux/seq_file.h> | ||
31 | #include <linux/mount.h> | ||
32 | #include <linux/nfs_idmap.h> | ||
33 | #include <linux/vfs.h> | ||
34 | #include <linux/namei.h> | ||
35 | #include <linux/namespace.h> | ||
36 | #include <linux/security.h> | ||
37 | |||
38 | #include <asm/system.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #include "nfs4_fs.h" | ||
42 | #include "delegation.h" | ||
43 | #include "internal.h" | ||
44 | |||
45 | #define NFSDBG_FACILITY NFSDBG_CLIENT | ||
46 | #define NFS_PARANOIA 1 | ||
47 | |||
48 | /* | ||
49 | * get an NFS2/NFS3 root dentry from the root filehandle | ||
50 | */ | ||
51 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | ||
52 | { | ||
53 | struct nfs_server *server = NFS_SB(sb); | ||
54 | struct nfs_fsinfo fsinfo; | ||
55 | struct nfs_fattr fattr; | ||
56 | struct dentry *mntroot; | ||
57 | struct inode *inode; | ||
58 | int error; | ||
59 | |||
60 | /* create a dummy root dentry with dummy inode for this superblock */ | ||
61 | if (!sb->s_root) { | ||
62 | struct nfs_fh dummyfh; | ||
63 | struct dentry *root; | ||
64 | struct inode *iroot; | ||
65 | |||
66 | memset(&dummyfh, 0, sizeof(dummyfh)); | ||
67 | memset(&fattr, 0, sizeof(fattr)); | ||
68 | nfs_fattr_init(&fattr); | ||
69 | fattr.valid = NFS_ATTR_FATTR; | ||
70 | fattr.type = NFDIR; | ||
71 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | ||
72 | fattr.nlink = 2; | ||
73 | |||
74 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | ||
75 | if (IS_ERR(iroot)) | ||
76 | return ERR_PTR(PTR_ERR(iroot)); | ||
77 | |||
78 | root = d_alloc_root(iroot); | ||
79 | if (!root) { | ||
80 | iput(iroot); | ||
81 | return ERR_PTR(-ENOMEM); | ||
82 | } | ||
83 | |||
84 | sb->s_root = root; | ||
85 | } | ||
86 | |||
87 | /* get the actual root for this mount */ | ||
88 | fsinfo.fattr = &fattr; | ||
89 | |||
90 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | ||
91 | if (error < 0) { | ||
92 | dprintk("nfs_get_root: getattr error = %d\n", -error); | ||
93 | return ERR_PTR(error); | ||
94 | } | ||
95 | |||
96 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); | ||
97 | if (IS_ERR(inode)) { | ||
98 | dprintk("nfs_get_root: get root inode failed\n"); | ||
99 | return ERR_PTR(PTR_ERR(inode)); | ||
100 | } | ||
101 | |||
102 | /* root dentries normally start off anonymous and get spliced in later | ||
103 | * if the dentry tree reaches them; however if the dentry already | ||
104 | * exists, we'll pick it up at this point and use it as the root | ||
105 | */ | ||
106 | mntroot = d_alloc_anon(inode); | ||
107 | if (!mntroot) { | ||
108 | iput(inode); | ||
109 | dprintk("nfs_get_root: get root dentry failed\n"); | ||
110 | return ERR_PTR(-ENOMEM); | ||
111 | } | ||
112 | |||
113 | security_d_instantiate(mntroot, inode); | ||
114 | |||
115 | if (!mntroot->d_op) | ||
116 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | ||
117 | |||
118 | return mntroot; | ||
119 | } | ||
120 | |||
121 | #ifdef CONFIG_NFS_V4 | ||
122 | |||
123 | /* | ||
124 | * Do a simple pathwalk from the root FH of the server to the nominated target | ||
125 | * of the mountpoint | ||
126 | * - give error on symlinks | ||
127 | * - give error on ".." occurring in the path | ||
128 | * - follow traversals | ||
129 | */ | ||
130 | int nfs4_path_walk(struct nfs_server *server, | ||
131 | struct nfs_fh *mntfh, | ||
132 | const char *path) | ||
133 | { | ||
134 | struct nfs_fsinfo fsinfo; | ||
135 | struct nfs_fattr fattr; | ||
136 | struct nfs_fh lastfh; | ||
137 | struct qstr name; | ||
138 | int ret; | ||
139 | //int referral_count = 0; | ||
140 | |||
141 | dprintk("--> nfs4_path_walk(,,%s)\n", path); | ||
142 | |||
143 | fsinfo.fattr = &fattr; | ||
144 | nfs_fattr_init(&fattr); | ||
145 | |||
146 | if (*path++ != '/') { | ||
147 | dprintk("nfs4_get_root: Path does not begin with a slash\n"); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | /* Start by getting the root filehandle from the server */ | ||
152 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | ||
153 | if (ret < 0) { | ||
154 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | if (fattr.type != NFDIR) { | ||
159 | printk(KERN_ERR "nfs4_get_root:" | ||
160 | " getroot encountered non-directory\n"); | ||
161 | return -ENOTDIR; | ||
162 | } | ||
163 | |||
164 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
165 | printk(KERN_ERR "nfs4_get_root:" | ||
166 | " getroot obtained referral\n"); | ||
167 | return -EREMOTE; | ||
168 | } | ||
169 | |||
170 | next_component: | ||
171 | dprintk("Next: %s\n", path); | ||
172 | |||
173 | /* extract the next bit of the path */ | ||
174 | if (!*path) | ||
175 | goto path_walk_complete; | ||
176 | |||
177 | name.name = path; | ||
178 | while (*path && *path != '/') | ||
179 | path++; | ||
180 | name.len = path - (const char *) name.name; | ||
181 | |||
182 | eat_dot_dir: | ||
183 | while (*path == '/') | ||
184 | path++; | ||
185 | |||
186 | if (path[0] == '.' && (path[1] == '/' || !path[1])) { | ||
187 | path += 2; | ||
188 | goto eat_dot_dir; | ||
189 | } | ||
190 | |||
191 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) | ||
192 | ) { | ||
193 | printk(KERN_ERR "nfs4_get_root:" | ||
194 | " Mount path contains reference to \"..\"\n"); | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | |||
198 | /* lookup the next FH in the sequence */ | ||
199 | memcpy(&lastfh, mntfh, sizeof(lastfh)); | ||
200 | |||
201 | dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); | ||
202 | |||
203 | ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name, | ||
204 | mntfh, &fattr); | ||
205 | if (ret < 0) { | ||
206 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | if (fattr.type != NFDIR) { | ||
211 | printk(KERN_ERR "nfs4_get_root:" | ||
212 | " lookupfh encountered non-directory\n"); | ||
213 | return -ENOTDIR; | ||
214 | } | ||
215 | |||
216 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
217 | printk(KERN_ERR "nfs4_get_root:" | ||
218 | " lookupfh obtained referral\n"); | ||
219 | return -EREMOTE; | ||
220 | } | ||
221 | |||
222 | goto next_component; | ||
223 | |||
224 | path_walk_complete: | ||
225 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | ||
226 | dprintk("<-- nfs4_path_walk() = 0\n"); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * get an NFS4 root dentry from the root filehandle | ||
232 | */ | ||
233 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | ||
234 | { | ||
235 | struct nfs_server *server = NFS_SB(sb); | ||
236 | struct nfs_fattr fattr; | ||
237 | struct dentry *mntroot; | ||
238 | struct inode *inode; | ||
239 | int error; | ||
240 | |||
241 | dprintk("--> nfs4_get_root()\n"); | ||
242 | |||
243 | /* create a dummy root dentry with dummy inode for this superblock */ | ||
244 | if (!sb->s_root) { | ||
245 | struct nfs_fh dummyfh; | ||
246 | struct dentry *root; | ||
247 | struct inode *iroot; | ||
248 | |||
249 | memset(&dummyfh, 0, sizeof(dummyfh)); | ||
250 | memset(&fattr, 0, sizeof(fattr)); | ||
251 | nfs_fattr_init(&fattr); | ||
252 | fattr.valid = NFS_ATTR_FATTR; | ||
253 | fattr.type = NFDIR; | ||
254 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | ||
255 | fattr.nlink = 2; | ||
256 | |||
257 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | ||
258 | if (IS_ERR(iroot)) | ||
259 | return ERR_PTR(PTR_ERR(iroot)); | ||
260 | |||
261 | root = d_alloc_root(iroot); | ||
262 | if (!root) { | ||
263 | iput(iroot); | ||
264 | return ERR_PTR(-ENOMEM); | ||
265 | } | ||
266 | |||
267 | sb->s_root = root; | ||
268 | } | ||
269 | |||
270 | /* get the info about the server and filesystem */ | ||
271 | error = nfs4_server_capabilities(server, mntfh); | ||
272 | if (error < 0) { | ||
273 | dprintk("nfs_get_root: getcaps error = %d\n", | ||
274 | -error); | ||
275 | return ERR_PTR(error); | ||
276 | } | ||
277 | |||
278 | /* get the actual root for this mount */ | ||
279 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | ||
280 | if (error < 0) { | ||
281 | dprintk("nfs_get_root: getattr error = %d\n", -error); | ||
282 | return ERR_PTR(error); | ||
283 | } | ||
284 | |||
285 | inode = nfs_fhget(sb, mntfh, &fattr); | ||
286 | if (IS_ERR(inode)) { | ||
287 | dprintk("nfs_get_root: get root inode failed\n"); | ||
288 | return ERR_PTR(PTR_ERR(inode)); | ||
289 | } | ||
290 | |||
291 | /* root dentries normally start off anonymous and get spliced in later | ||
292 | * if the dentry tree reaches them; however if the dentry already | ||
293 | * exists, we'll pick it up at this point and use it as the root | ||
294 | */ | ||
295 | mntroot = d_alloc_anon(inode); | ||
296 | if (!mntroot) { | ||
297 | iput(inode); | ||
298 | dprintk("nfs_get_root: get root dentry failed\n"); | ||
299 | return ERR_PTR(-ENOMEM); | ||
300 | } | ||
301 | |||
302 | security_d_instantiate(mntroot, inode); | ||
303 | |||
304 | if (!mntroot->d_op) | ||
305 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | ||
306 | |||
307 | dprintk("<-- nfs4_get_root()\n"); | ||
308 | return mntroot; | ||
309 | } | ||
310 | |||
311 | #endif /* CONFIG_NFS_V4 */ | ||
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 07a5dd57646e..82ad7110a1c0 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -57,6 +57,20 @@ | |||
57 | /* Default cache timeout is 10 minutes */ | 57 | /* Default cache timeout is 10 minutes */ |
58 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; | 58 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; |
59 | 59 | ||
60 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | ||
61 | { | ||
62 | char *endp; | ||
63 | int num = simple_strtol(val, &endp, 0); | ||
64 | int jif = num * HZ; | ||
65 | if (endp == val || *endp || num < 0 || jif < num) | ||
66 | return -EINVAL; | ||
67 | *((int *)kp->arg) = jif; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | ||
72 | &nfs_idmap_cache_timeout, 0644); | ||
73 | |||
60 | struct idmap_hashent { | 74 | struct idmap_hashent { |
61 | unsigned long ih_expires; | 75 | unsigned long ih_expires; |
62 | __u32 ih_id; | 76 | __u32 ih_id; |
@@ -70,7 +84,6 @@ struct idmap_hashtable { | |||
70 | }; | 84 | }; |
71 | 85 | ||
72 | struct idmap { | 86 | struct idmap { |
73 | char idmap_path[48]; | ||
74 | struct dentry *idmap_dentry; | 87 | struct dentry *idmap_dentry; |
75 | wait_queue_head_t idmap_wq; | 88 | wait_queue_head_t idmap_wq; |
76 | struct idmap_msg idmap_im; | 89 | struct idmap_msg idmap_im; |
@@ -94,24 +107,23 @@ static struct rpc_pipe_ops idmap_upcall_ops = { | |||
94 | .destroy_msg = idmap_pipe_destroy_msg, | 107 | .destroy_msg = idmap_pipe_destroy_msg, |
95 | }; | 108 | }; |
96 | 109 | ||
97 | void | 110 | int |
98 | nfs_idmap_new(struct nfs4_client *clp) | 111 | nfs_idmap_new(struct nfs_client *clp) |
99 | { | 112 | { |
100 | struct idmap *idmap; | 113 | struct idmap *idmap; |
114 | int error; | ||
101 | 115 | ||
102 | if (clp->cl_idmap != NULL) | 116 | BUG_ON(clp->cl_idmap != NULL); |
103 | return; | ||
104 | if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) | ||
105 | return; | ||
106 | 117 | ||
107 | snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), | 118 | if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) |
108 | "%s/idmap", clp->cl_rpcclient->cl_pathname); | 119 | return -ENOMEM; |
109 | 120 | ||
110 | idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path, | 121 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", |
111 | idmap, &idmap_upcall_ops, 0); | 122 | idmap, &idmap_upcall_ops, 0); |
112 | if (IS_ERR(idmap->idmap_dentry)) { | 123 | if (IS_ERR(idmap->idmap_dentry)) { |
124 | error = PTR_ERR(idmap->idmap_dentry); | ||
113 | kfree(idmap); | 125 | kfree(idmap); |
114 | return; | 126 | return error; |
115 | } | 127 | } |
116 | 128 | ||
117 | mutex_init(&idmap->idmap_lock); | 129 | mutex_init(&idmap->idmap_lock); |
@@ -121,10 +133,11 @@ nfs_idmap_new(struct nfs4_client *clp) | |||
121 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; | 133 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; |
122 | 134 | ||
123 | clp->cl_idmap = idmap; | 135 | clp->cl_idmap = idmap; |
136 | return 0; | ||
124 | } | 137 | } |
125 | 138 | ||
126 | void | 139 | void |
127 | nfs_idmap_delete(struct nfs4_client *clp) | 140 | nfs_idmap_delete(struct nfs_client *clp) |
128 | { | 141 | { |
129 | struct idmap *idmap = clp->cl_idmap; | 142 | struct idmap *idmap = clp->cl_idmap; |
130 | 143 | ||
@@ -477,27 +490,27 @@ static unsigned int fnvhash32(const void *buf, size_t buflen) | |||
477 | return (hash); | 490 | return (hash); |
478 | } | 491 | } |
479 | 492 | ||
480 | int nfs_map_name_to_uid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid) | 493 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
481 | { | 494 | { |
482 | struct idmap *idmap = clp->cl_idmap; | 495 | struct idmap *idmap = clp->cl_idmap; |
483 | 496 | ||
484 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); | 497 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); |
485 | } | 498 | } |
486 | 499 | ||
487 | int nfs_map_group_to_gid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid) | 500 | int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
488 | { | 501 | { |
489 | struct idmap *idmap = clp->cl_idmap; | 502 | struct idmap *idmap = clp->cl_idmap; |
490 | 503 | ||
491 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); | 504 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); |
492 | } | 505 | } |
493 | 506 | ||
494 | int nfs_map_uid_to_name(struct nfs4_client *clp, __u32 uid, char *buf) | 507 | int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf) |
495 | { | 508 | { |
496 | struct idmap *idmap = clp->cl_idmap; | 509 | struct idmap *idmap = clp->cl_idmap; |
497 | 510 | ||
498 | return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); | 511 | return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); |
499 | } | 512 | } |
500 | int nfs_map_gid_to_group(struct nfs4_client *clp, __u32 uid, char *buf) | 513 | int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf) |
501 | { | 514 | { |
502 | struct idmap *idmap = clp->cl_idmap; | 515 | struct idmap *idmap = clp->cl_idmap; |
503 | 516 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d349fb2245da..e8c143d182c4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -76,19 +76,14 @@ int nfs_write_inode(struct inode *inode, int sync) | |||
76 | 76 | ||
77 | void nfs_clear_inode(struct inode *inode) | 77 | void nfs_clear_inode(struct inode *inode) |
78 | { | 78 | { |
79 | struct nfs_inode *nfsi = NFS_I(inode); | ||
80 | struct rpc_cred *cred; | ||
81 | |||
82 | /* | 79 | /* |
83 | * The following should never happen... | 80 | * The following should never happen... |
84 | */ | 81 | */ |
85 | BUG_ON(nfs_have_writebacks(inode)); | 82 | BUG_ON(nfs_have_writebacks(inode)); |
86 | BUG_ON (!list_empty(&nfsi->open_files)); | 83 | BUG_ON(!list_empty(&NFS_I(inode)->open_files)); |
84 | BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0); | ||
87 | nfs_zap_acl_cache(inode); | 85 | nfs_zap_acl_cache(inode); |
88 | cred = nfsi->cache_access.cred; | 86 | nfs_access_zap_cache(inode); |
89 | if (cred) | ||
90 | put_rpccred(cred); | ||
91 | BUG_ON(atomic_read(&nfsi->data_updates) != 0); | ||
92 | } | 87 | } |
93 | 88 | ||
94 | /** | 89 | /** |
@@ -242,13 +237,13 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
242 | /* Why so? Because we want revalidate for devices/FIFOs, and | 237 | /* Why so? Because we want revalidate for devices/FIFOs, and |
243 | * that's precisely what we have in nfs_file_inode_operations. | 238 | * that's precisely what we have in nfs_file_inode_operations. |
244 | */ | 239 | */ |
245 | inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops; | 240 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops; |
246 | if (S_ISREG(inode->i_mode)) { | 241 | if (S_ISREG(inode->i_mode)) { |
247 | inode->i_fop = &nfs_file_operations; | 242 | inode->i_fop = &nfs_file_operations; |
248 | inode->i_data.a_ops = &nfs_file_aops; | 243 | inode->i_data.a_ops = &nfs_file_aops; |
249 | inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info; | 244 | inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info; |
250 | } else if (S_ISDIR(inode->i_mode)) { | 245 | } else if (S_ISDIR(inode->i_mode)) { |
251 | inode->i_op = NFS_SB(sb)->rpc_ops->dir_inode_ops; | 246 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; |
252 | inode->i_fop = &nfs_dir_operations; | 247 | inode->i_fop = &nfs_dir_operations; |
253 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) | 248 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) |
254 | && fattr->size <= NFS_LIMIT_READDIRPLUS) | 249 | && fattr->size <= NFS_LIMIT_READDIRPLUS) |
@@ -290,7 +285,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
290 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 285 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
291 | nfsi->attrtimeo_timestamp = jiffies; | 286 | nfsi->attrtimeo_timestamp = jiffies; |
292 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | 287 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); |
293 | nfsi->cache_access.cred = NULL; | 288 | nfsi->access_cache = RB_ROOT; |
294 | 289 | ||
295 | unlock_new_inode(inode); | 290 | unlock_new_inode(inode); |
296 | } else | 291 | } else |
@@ -722,13 +717,11 @@ void nfs_end_data_update(struct inode *inode) | |||
722 | { | 717 | { |
723 | struct nfs_inode *nfsi = NFS_I(inode); | 718 | struct nfs_inode *nfsi = NFS_I(inode); |
724 | 719 | ||
725 | if (!nfs_have_delegation(inode, FMODE_READ)) { | 720 | /* Directories: invalidate page cache */ |
726 | /* Directories and symlinks: invalidate page cache */ | 721 | if (S_ISDIR(inode->i_mode)) { |
727 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { | 722 | spin_lock(&inode->i_lock); |
728 | spin_lock(&inode->i_lock); | 723 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; |
729 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; | 724 | spin_unlock(&inode->i_lock); |
730 | spin_unlock(&inode->i_lock); | ||
731 | } | ||
732 | } | 725 | } |
733 | nfsi->cache_change_attribute = jiffies; | 726 | nfsi->cache_change_attribute = jiffies; |
734 | atomic_dec(&nfsi->data_updates); | 727 | atomic_dec(&nfsi->data_updates); |
@@ -847,6 +840,12 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
847 | * | 840 | * |
848 | * After an operation that has changed the inode metadata, mark the | 841 | * After an operation that has changed the inode metadata, mark the |
849 | * attribute cache as being invalid, then try to update it. | 842 | * attribute cache as being invalid, then try to update it. |
843 | * | ||
844 | * NB: if the server didn't return any post op attributes, this | ||
845 | * function will force the retrieval of attributes before the next | ||
846 | * NFS request. Thus it should be used only for operations that | ||
847 | * are expected to change one or more attributes, to avoid | ||
848 | * unnecessary NFS requests and trips through nfs_update_inode(). | ||
850 | */ | 849 | */ |
851 | int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) | 850 | int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) |
852 | { | 851 | { |
@@ -1025,7 +1024,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1025 | out_fileid: | 1024 | out_fileid: |
1026 | printk(KERN_ERR "NFS: server %s error: fileid changed\n" | 1025 | printk(KERN_ERR "NFS: server %s error: fileid changed\n" |
1027 | "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", | 1026 | "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", |
1028 | NFS_SERVER(inode)->hostname, inode->i_sb->s_id, | 1027 | NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id, |
1029 | (long long)nfsi->fileid, (long long)fattr->fileid); | 1028 | (long long)nfsi->fileid, (long long)fattr->fileid); |
1030 | goto out_err; | 1029 | goto out_err; |
1031 | } | 1030 | } |
@@ -1109,6 +1108,8 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | |||
1109 | INIT_LIST_HEAD(&nfsi->dirty); | 1108 | INIT_LIST_HEAD(&nfsi->dirty); |
1110 | INIT_LIST_HEAD(&nfsi->commit); | 1109 | INIT_LIST_HEAD(&nfsi->commit); |
1111 | INIT_LIST_HEAD(&nfsi->open_files); | 1110 | INIT_LIST_HEAD(&nfsi->open_files); |
1111 | INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); | ||
1112 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); | ||
1112 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); | 1113 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); |
1113 | atomic_set(&nfsi->data_updates, 0); | 1114 | atomic_set(&nfsi->data_updates, 0); |
1114 | nfsi->ndirty = 0; | 1115 | nfsi->ndirty = 0; |
@@ -1144,6 +1145,10 @@ static int __init init_nfs_fs(void) | |||
1144 | { | 1145 | { |
1145 | int err; | 1146 | int err; |
1146 | 1147 | ||
1148 | err = nfs_fs_proc_init(); | ||
1149 | if (err) | ||
1150 | goto out5; | ||
1151 | |||
1147 | err = nfs_init_nfspagecache(); | 1152 | err = nfs_init_nfspagecache(); |
1148 | if (err) | 1153 | if (err) |
1149 | goto out4; | 1154 | goto out4; |
@@ -1184,6 +1189,8 @@ out2: | |||
1184 | out3: | 1189 | out3: |
1185 | nfs_destroy_nfspagecache(); | 1190 | nfs_destroy_nfspagecache(); |
1186 | out4: | 1191 | out4: |
1192 | nfs_fs_proc_exit(); | ||
1193 | out5: | ||
1187 | return err; | 1194 | return err; |
1188 | } | 1195 | } |
1189 | 1196 | ||
@@ -1198,6 +1205,7 @@ static void __exit exit_nfs_fs(void) | |||
1198 | rpc_proc_unregister("nfs"); | 1205 | rpc_proc_unregister("nfs"); |
1199 | #endif | 1206 | #endif |
1200 | unregister_nfs_fs(); | 1207 | unregister_nfs_fs(); |
1208 | nfs_fs_proc_exit(); | ||
1201 | } | 1209 | } |
1202 | 1210 | ||
1203 | /* Not quite true; I just maintain it */ | 1211 | /* Not quite true; I just maintain it */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e4f4e5def0fc..bea0b016bd70 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -4,6 +4,18 @@ | |||
4 | 4 | ||
5 | #include <linux/mount.h> | 5 | #include <linux/mount.h> |
6 | 6 | ||
7 | struct nfs_string; | ||
8 | struct nfs_mount_data; | ||
9 | struct nfs4_mount_data; | ||
10 | |||
11 | /* Maximum number of readahead requests | ||
12 | * FIXME: this should really be a sysctl so that users may tune it to suit | ||
13 | * their needs. People that do NFS over a slow network, might for | ||
14 | * instance want to reduce it to something closer to 1 for improved | ||
15 | * interactive response. | ||
16 | */ | ||
17 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | ||
18 | |||
7 | struct nfs_clone_mount { | 19 | struct nfs_clone_mount { |
8 | const struct super_block *sb; | 20 | const struct super_block *sb; |
9 | const struct dentry *dentry; | 21 | const struct dentry *dentry; |
@@ -15,7 +27,40 @@ struct nfs_clone_mount { | |||
15 | rpc_authflavor_t authflavor; | 27 | rpc_authflavor_t authflavor; |
16 | }; | 28 | }; |
17 | 29 | ||
18 | /* namespace-nfs4.c */ | 30 | /* client.c */ |
31 | extern struct rpc_program nfs_program; | ||
32 | |||
33 | extern void nfs_put_client(struct nfs_client *); | ||
34 | extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int); | ||
35 | extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *, | ||
36 | struct nfs_fh *); | ||
37 | extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *, | ||
38 | const char *, | ||
39 | const struct sockaddr_in *, | ||
40 | const char *, | ||
41 | const char *, | ||
42 | rpc_authflavor_t, | ||
43 | struct nfs_fh *); | ||
44 | extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, | ||
45 | struct nfs_fh *); | ||
46 | extern void nfs_free_server(struct nfs_server *server); | ||
47 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | ||
48 | struct nfs_fh *, | ||
49 | struct nfs_fattr *); | ||
50 | #ifdef CONFIG_PROC_FS | ||
51 | extern int __init nfs_fs_proc_init(void); | ||
52 | extern void nfs_fs_proc_exit(void); | ||
53 | #else | ||
54 | static inline int nfs_fs_proc_init(void) | ||
55 | { | ||
56 | return 0; | ||
57 | } | ||
58 | static inline void nfs_fs_proc_exit(void) | ||
59 | { | ||
60 | } | ||
61 | #endif | ||
62 | |||
63 | /* nfs4namespace.c */ | ||
19 | #ifdef CONFIG_NFS_V4 | 64 | #ifdef CONFIG_NFS_V4 |
20 | extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry); | 65 | extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry); |
21 | #else | 66 | #else |
@@ -46,6 +91,7 @@ extern void nfs_destroy_directcache(void); | |||
46 | #endif | 91 | #endif |
47 | 92 | ||
48 | /* nfs2xdr.c */ | 93 | /* nfs2xdr.c */ |
94 | extern int nfs_stat_to_errno(int); | ||
49 | extern struct rpc_procinfo nfs_procedures[]; | 95 | extern struct rpc_procinfo nfs_procedures[]; |
50 | extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); | 96 | extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); |
51 | 97 | ||
@@ -54,8 +100,9 @@ extern struct rpc_procinfo nfs3_procedures[]; | |||
54 | extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); | 100 | extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); |
55 | 101 | ||
56 | /* nfs4xdr.c */ | 102 | /* nfs4xdr.c */ |
57 | extern int nfs_stat_to_errno(int); | 103 | #ifdef CONFIG_NFS_V4 |
58 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 104 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
105 | #endif | ||
59 | 106 | ||
60 | /* nfs4proc.c */ | 107 | /* nfs4proc.c */ |
61 | #ifdef CONFIG_NFS_V4 | 108 | #ifdef CONFIG_NFS_V4 |
@@ -66,6 +113,9 @@ extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | |||
66 | struct page *page); | 113 | struct page *page); |
67 | #endif | 114 | #endif |
68 | 115 | ||
116 | /* dir.c */ | ||
117 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); | ||
118 | |||
69 | /* inode.c */ | 119 | /* inode.c */ |
70 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 120 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
71 | extern void nfs_destroy_inode(struct inode *); | 121 | extern void nfs_destroy_inode(struct inode *); |
@@ -76,10 +126,10 @@ extern void nfs4_clear_inode(struct inode *); | |||
76 | #endif | 126 | #endif |
77 | 127 | ||
78 | /* super.c */ | 128 | /* super.c */ |
79 | extern struct file_system_type nfs_referral_nfs4_fs_type; | 129 | extern struct file_system_type nfs_xdev_fs_type; |
80 | extern struct file_system_type clone_nfs_fs_type; | ||
81 | #ifdef CONFIG_NFS_V4 | 130 | #ifdef CONFIG_NFS_V4 |
82 | extern struct file_system_type clone_nfs4_fs_type; | 131 | extern struct file_system_type nfs4_xdev_fs_type; |
132 | extern struct file_system_type nfs4_referral_fs_type; | ||
83 | #endif | 133 | #endif |
84 | 134 | ||
85 | extern struct rpc_stat nfs_rpcstat; | 135 | extern struct rpc_stat nfs_rpcstat; |
@@ -88,30 +138,30 @@ extern int __init register_nfs_fs(void); | |||
88 | extern void __exit unregister_nfs_fs(void); | 138 | extern void __exit unregister_nfs_fs(void); |
89 | 139 | ||
90 | /* namespace.c */ | 140 | /* namespace.c */ |
91 | extern char *nfs_path(const char *base, const struct dentry *dentry, | 141 | extern char *nfs_path(const char *base, |
142 | const struct dentry *droot, | ||
143 | const struct dentry *dentry, | ||
92 | char *buffer, ssize_t buflen); | 144 | char *buffer, ssize_t buflen); |
93 | 145 | ||
94 | /* | 146 | /* getroot.c */ |
95 | * Determine the mount path as a string | 147 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); |
96 | */ | ||
97 | static inline char * | ||
98 | nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen) | ||
99 | { | ||
100 | #ifdef CONFIG_NFS_V4 | 148 | #ifdef CONFIG_NFS_V4 |
101 | return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen); | 149 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); |
102 | #else | 150 | |
103 | return NULL; | 151 | extern int nfs4_path_walk(struct nfs_server *server, |
152 | struct nfs_fh *mntfh, | ||
153 | const char *path); | ||
104 | #endif | 154 | #endif |
105 | } | ||
106 | 155 | ||
107 | /* | 156 | /* |
108 | * Determine the device name as a string | 157 | * Determine the device name as a string |
109 | */ | 158 | */ |
110 | static inline char *nfs_devname(const struct vfsmount *mnt_parent, | 159 | static inline char *nfs_devname(const struct vfsmount *mnt_parent, |
111 | const struct dentry *dentry, | 160 | const struct dentry *dentry, |
112 | char *buffer, ssize_t buflen) | 161 | char *buffer, ssize_t buflen) |
113 | { | 162 | { |
114 | return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen); | 163 | return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root, |
164 | dentry, buffer, buflen); | ||
115 | } | 165 | } |
116 | 166 | ||
117 | /* | 167 | /* |
@@ -167,20 +217,3 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize) | |||
167 | if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0) | 217 | if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0) |
168 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 218 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
169 | } | 219 | } |
170 | |||
171 | /* | ||
172 | * Check if the string represents a "valid" IPv4 address | ||
173 | */ | ||
174 | static inline int valid_ipaddr4(const char *buf) | ||
175 | { | ||
176 | int rc, count, in[4]; | ||
177 | |||
178 | rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); | ||
179 | if (rc != 4) | ||
180 | return -EINVAL; | ||
181 | for (count = 0; count < 4; count++) { | ||
182 | if (in[count] > 255) | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | return 0; | ||
186 | } | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 445abb4d4214..d507b021207f 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/net.h> | 14 | #include <linux/net.h> |
15 | #include <linux/in.h> | 15 | #include <linux/in.h> |
16 | #include <linux/sunrpc/clnt.h> | 16 | #include <linux/sunrpc/clnt.h> |
17 | #include <linux/sunrpc/xprt.h> | ||
18 | #include <linux/sunrpc/sched.h> | 17 | #include <linux/sunrpc/sched.h> |
19 | #include <linux/nfs_fs.h> | 18 | #include <linux/nfs_fs.h> |
20 | 19 | ||
@@ -77,22 +76,19 @@ static struct rpc_clnt * | |||
77 | mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, | 76 | mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, |
78 | int protocol) | 77 | int protocol) |
79 | { | 78 | { |
80 | struct rpc_xprt *xprt; | 79 | struct rpc_create_args args = { |
81 | struct rpc_clnt *clnt; | 80 | .protocol = protocol, |
82 | 81 | .address = (struct sockaddr *)srvaddr, | |
83 | xprt = xprt_create_proto(protocol, srvaddr, NULL); | 82 | .addrsize = sizeof(*srvaddr), |
84 | if (IS_ERR(xprt)) | 83 | .servername = hostname, |
85 | return (struct rpc_clnt *)xprt; | 84 | .program = &mnt_program, |
86 | 85 | .version = version, | |
87 | clnt = rpc_create_client(xprt, hostname, | 86 | .authflavor = RPC_AUTH_UNIX, |
88 | &mnt_program, version, | 87 | .flags = (RPC_CLNT_CREATE_ONESHOT | |
89 | RPC_AUTH_UNIX); | 88 | RPC_CLNT_CREATE_INTR), |
90 | if (!IS_ERR(clnt)) { | 89 | }; |
91 | clnt->cl_softrtry = 1; | 90 | |
92 | clnt->cl_oneshot = 1; | 91 | return rpc_create(&args); |
93 | clnt->cl_intr = 1; | ||
94 | } | ||
95 | return clnt; | ||
96 | } | 92 | } |
97 | 93 | ||
98 | /* | 94 | /* |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 86b3169c8cac..77b00684894d 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * linux/fs/nfs/namespace.c | 2 | * linux/fs/nfs/namespace.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> | 4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> |
5 | * - Modified by David Howells <dhowells@redhat.com> | ||
5 | * | 6 | * |
6 | * NFS namespace | 7 | * NFS namespace |
7 | */ | 8 | */ |
@@ -28,6 +29,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; | |||
28 | /* | 29 | /* |
29 | * nfs_path - reconstruct the path given an arbitrary dentry | 30 | * nfs_path - reconstruct the path given an arbitrary dentry |
30 | * @base - arbitrary string to prepend to the path | 31 | * @base - arbitrary string to prepend to the path |
32 | * @droot - pointer to root dentry for mountpoint | ||
31 | * @dentry - pointer to dentry | 33 | * @dentry - pointer to dentry |
32 | * @buffer - result buffer | 34 | * @buffer - result buffer |
33 | * @buflen - length of buffer | 35 | * @buflen - length of buffer |
@@ -38,7 +40,9 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; | |||
38 | * This is mainly for use in figuring out the path on the | 40 | * This is mainly for use in figuring out the path on the |
39 | * server side when automounting on top of an existing partition. | 41 | * server side when automounting on top of an existing partition. |
40 | */ | 42 | */ |
41 | char *nfs_path(const char *base, const struct dentry *dentry, | 43 | char *nfs_path(const char *base, |
44 | const struct dentry *droot, | ||
45 | const struct dentry *dentry, | ||
42 | char *buffer, ssize_t buflen) | 46 | char *buffer, ssize_t buflen) |
43 | { | 47 | { |
44 | char *end = buffer+buflen; | 48 | char *end = buffer+buflen; |
@@ -47,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry, | |||
47 | *--end = '\0'; | 51 | *--end = '\0'; |
48 | buflen--; | 52 | buflen--; |
49 | spin_lock(&dcache_lock); | 53 | spin_lock(&dcache_lock); |
50 | while (!IS_ROOT(dentry)) { | 54 | while (!IS_ROOT(dentry) && dentry != droot) { |
51 | namelen = dentry->d_name.len; | 55 | namelen = dentry->d_name.len; |
52 | buflen -= namelen + 1; | 56 | buflen -= namelen + 1; |
53 | if (buflen < 0) | 57 | if (buflen < 0) |
@@ -96,15 +100,18 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
96 | struct nfs_fattr fattr; | 100 | struct nfs_fattr fattr; |
97 | int err; | 101 | int err; |
98 | 102 | ||
103 | dprintk("--> nfs_follow_mountpoint()\n"); | ||
104 | |||
99 | BUG_ON(IS_ROOT(dentry)); | 105 | BUG_ON(IS_ROOT(dentry)); |
100 | dprintk("%s: enter\n", __FUNCTION__); | 106 | dprintk("%s: enter\n", __FUNCTION__); |
101 | dput(nd->dentry); | 107 | dput(nd->dentry); |
102 | nd->dentry = dget(dentry); | 108 | nd->dentry = dget(dentry); |
103 | if (d_mountpoint(nd->dentry)) | 109 | |
104 | goto out_follow; | ||
105 | /* Look it up again */ | 110 | /* Look it up again */ |
106 | parent = dget_parent(nd->dentry); | 111 | parent = dget_parent(nd->dentry); |
107 | err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr); | 112 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, |
113 | &nd->dentry->d_name, | ||
114 | &fh, &fattr); | ||
108 | dput(parent); | 115 | dput(parent); |
109 | if (err != 0) | 116 | if (err != 0) |
110 | goto out_err; | 117 | goto out_err; |
@@ -132,6 +139,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
132 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | 139 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); |
133 | out: | 140 | out: |
134 | dprintk("%s: done, returned %d\n", __FUNCTION__, err); | 141 | dprintk("%s: done, returned %d\n", __FUNCTION__, err); |
142 | |||
143 | dprintk("<-- nfs_follow_mountpoint() = %d\n", err); | ||
135 | return ERR_PTR(err); | 144 | return ERR_PTR(err); |
136 | out_err: | 145 | out_err: |
137 | path_release(nd); | 146 | path_release(nd); |
@@ -172,22 +181,23 @@ void nfs_release_automount_timer(void) | |||
172 | /* | 181 | /* |
173 | * Clone a mountpoint of the appropriate type | 182 | * Clone a mountpoint of the appropriate type |
174 | */ | 183 | */ |
175 | static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname, | 184 | static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, |
185 | const char *devname, | ||
176 | struct nfs_clone_mount *mountdata) | 186 | struct nfs_clone_mount *mountdata) |
177 | { | 187 | { |
178 | #ifdef CONFIG_NFS_V4 | 188 | #ifdef CONFIG_NFS_V4 |
179 | struct vfsmount *mnt = NULL; | 189 | struct vfsmount *mnt = NULL; |
180 | switch (server->rpc_ops->version) { | 190 | switch (server->nfs_client->cl_nfsversion) { |
181 | case 2: | 191 | case 2: |
182 | case 3: | 192 | case 3: |
183 | mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata); | 193 | mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); |
184 | break; | 194 | break; |
185 | case 4: | 195 | case 4: |
186 | mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata); | 196 | mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata); |
187 | } | 197 | } |
188 | return mnt; | 198 | return mnt; |
189 | #else | 199 | #else |
190 | return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata); | 200 | return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); |
191 | #endif | 201 | #endif |
192 | } | 202 | } |
193 | 203 | ||
@@ -213,6 +223,8 @@ struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, | |||
213 | char *page = (char *) __get_free_page(GFP_USER); | 223 | char *page = (char *) __get_free_page(GFP_USER); |
214 | char *devname; | 224 | char *devname; |
215 | 225 | ||
226 | dprintk("--> nfs_do_submount()\n"); | ||
227 | |||
216 | dprintk("%s: submounting on %s/%s\n", __FUNCTION__, | 228 | dprintk("%s: submounting on %s/%s\n", __FUNCTION__, |
217 | dentry->d_parent->d_name.name, | 229 | dentry->d_parent->d_name.name, |
218 | dentry->d_name.name); | 230 | dentry->d_name.name); |
@@ -227,5 +239,7 @@ free_page: | |||
227 | free_page((unsigned long)page); | 239 | free_page((unsigned long)page); |
228 | out: | 240 | out: |
229 | dprintk("%s: done\n", __FUNCTION__); | 241 | dprintk("%s: done\n", __FUNCTION__); |
242 | |||
243 | dprintk("<-- nfs_do_submount() = %p\n", mnt); | ||
230 | return mnt; | 244 | return mnt; |
231 | } | 245 | } |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 67391eef6b93..b49501fc0a79 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -51,7 +51,7 @@ | |||
51 | #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) | 51 | #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) |
52 | #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) | 52 | #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) |
53 | #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) | 53 | #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) |
54 | #define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz) | 54 | #define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz) |
55 | #define NFS_readdirargs_sz (NFS_fhandle_sz+2) | 55 | #define NFS_readdirargs_sz (NFS_fhandle_sz+2) |
56 | 56 | ||
57 | #define NFS_attrstat_sz (1+NFS_fattr_sz) | 57 | #define NFS_attrstat_sz (1+NFS_fattr_sz) |
@@ -351,11 +351,26 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args) | |||
351 | static int | 351 | static int |
352 | nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) | 352 | nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) |
353 | { | 353 | { |
354 | struct xdr_buf *sndbuf = &req->rq_snd_buf; | ||
355 | size_t pad; | ||
356 | |||
354 | p = xdr_encode_fhandle(p, args->fromfh); | 357 | p = xdr_encode_fhandle(p, args->fromfh); |
355 | p = xdr_encode_array(p, args->fromname, args->fromlen); | 358 | p = xdr_encode_array(p, args->fromname, args->fromlen); |
356 | p = xdr_encode_array(p, args->topath, args->tolen); | 359 | *p++ = htonl(args->pathlen); |
360 | sndbuf->len = xdr_adjust_iovec(sndbuf->head, p); | ||
361 | |||
362 | xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen); | ||
363 | |||
364 | /* | ||
365 | * xdr_encode_pages may have added a few bytes to ensure the | ||
366 | * pathname ends on a 4-byte boundary. Start encoding the | ||
367 | * attributes after the pad bytes. | ||
368 | */ | ||
369 | pad = sndbuf->tail->iov_len; | ||
370 | if (pad > 0) | ||
371 | p++; | ||
357 | p = xdr_encode_sattr(p, args->sattr); | 372 | p = xdr_encode_sattr(p, args->sattr); |
358 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | 373 | sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad; |
359 | return 0; | 374 | return 0; |
360 | } | 375 | } |
361 | 376 | ||
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 7143b1f82cea..f8688eaa0001 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -81,7 +81,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, | |||
81 | } | 81 | } |
82 | 82 | ||
83 | /* | 83 | /* |
84 | * Bare-bones access to getattr: this is for nfs_read_super. | 84 | * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb |
85 | */ | 85 | */ |
86 | static int | 86 | static int |
87 | nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 87 | nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -90,8 +90,8 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
90 | int status; | 90 | int status; |
91 | 91 | ||
92 | status = do_proc_get_root(server->client, fhandle, info); | 92 | status = do_proc_get_root(server->client, fhandle, info); |
93 | if (status && server->client_sys != server->client) | 93 | if (status && server->nfs_client->cl_rpcclient != server->client) |
94 | status = do_proc_get_root(server->client_sys, fhandle, info); | 94 | status = do_proc_get_root(server->nfs_client->cl_rpcclient, fhandle, info); |
95 | return status; | 95 | return status; |
96 | } | 96 | } |
97 | 97 | ||
@@ -544,23 +544,23 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | |||
544 | } | 544 | } |
545 | 545 | ||
546 | static int | 546 | static int |
547 | nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | 547 | nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, |
548 | struct iattr *sattr, struct nfs_fh *fhandle, | 548 | unsigned int len, struct iattr *sattr) |
549 | struct nfs_fattr *fattr) | ||
550 | { | 549 | { |
551 | struct nfs_fattr dir_attr; | 550 | struct nfs_fh fhandle; |
551 | struct nfs_fattr fattr, dir_attr; | ||
552 | struct nfs3_symlinkargs arg = { | 552 | struct nfs3_symlinkargs arg = { |
553 | .fromfh = NFS_FH(dir), | 553 | .fromfh = NFS_FH(dir), |
554 | .fromname = name->name, | 554 | .fromname = dentry->d_name.name, |
555 | .fromlen = name->len, | 555 | .fromlen = dentry->d_name.len, |
556 | .topath = path->name, | 556 | .pages = &page, |
557 | .tolen = path->len, | 557 | .pathlen = len, |
558 | .sattr = sattr | 558 | .sattr = sattr |
559 | }; | 559 | }; |
560 | struct nfs3_diropres res = { | 560 | struct nfs3_diropres res = { |
561 | .dir_attr = &dir_attr, | 561 | .dir_attr = &dir_attr, |
562 | .fh = fhandle, | 562 | .fh = &fhandle, |
563 | .fattr = fattr | 563 | .fattr = &fattr |
564 | }; | 564 | }; |
565 | struct rpc_message msg = { | 565 | struct rpc_message msg = { |
566 | .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], | 566 | .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], |
@@ -569,13 +569,19 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
569 | }; | 569 | }; |
570 | int status; | 570 | int status; |
571 | 571 | ||
572 | if (path->len > NFS3_MAXPATHLEN) | 572 | if (len > NFS3_MAXPATHLEN) |
573 | return -ENAMETOOLONG; | 573 | return -ENAMETOOLONG; |
574 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); | 574 | |
575 | dprintk("NFS call symlink %s\n", dentry->d_name.name); | ||
576 | |||
575 | nfs_fattr_init(&dir_attr); | 577 | nfs_fattr_init(&dir_attr); |
576 | nfs_fattr_init(fattr); | 578 | nfs_fattr_init(&fattr); |
577 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 579 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
578 | nfs_post_op_update_inode(dir, &dir_attr); | 580 | nfs_post_op_update_inode(dir, &dir_attr); |
581 | if (status != 0) | ||
582 | goto out; | ||
583 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
584 | out: | ||
579 | dprintk("NFS reply symlink: %d\n", status); | 585 | dprintk("NFS reply symlink: %d\n", status); |
580 | return status; | 586 | return status; |
581 | } | 587 | } |
@@ -785,7 +791,7 @@ nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
785 | 791 | ||
786 | dprintk("NFS call fsinfo\n"); | 792 | dprintk("NFS call fsinfo\n"); |
787 | nfs_fattr_init(info->fattr); | 793 | nfs_fattr_init(info->fattr); |
788 | status = rpc_call_sync(server->client_sys, &msg, 0); | 794 | status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); |
789 | dprintk("NFS reply fsinfo: %d\n", status); | 795 | dprintk("NFS reply fsinfo: %d\n", status); |
790 | return status; | 796 | return status; |
791 | } | 797 | } |
@@ -886,7 +892,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
886 | return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl); | 892 | return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl); |
887 | } | 893 | } |
888 | 894 | ||
889 | struct nfs_rpc_ops nfs_v3_clientops = { | 895 | const struct nfs_rpc_ops nfs_v3_clientops = { |
890 | .version = 3, /* protocol version */ | 896 | .version = 3, /* protocol version */ |
891 | .dentry_ops = &nfs_dentry_operations, | 897 | .dentry_ops = &nfs_dentry_operations, |
892 | .dir_inode_ops = &nfs3_dir_inode_operations, | 898 | .dir_inode_ops = &nfs3_dir_inode_operations, |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 0250269e9753..16556fa4effb 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #define NFS3_writeargs_sz (NFS3_fh_sz+5) | 56 | #define NFS3_writeargs_sz (NFS3_fh_sz+5) |
57 | #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) | 57 | #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) |
58 | #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) | 58 | #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) |
59 | #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz) | 59 | #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz) |
60 | #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) | 60 | #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) |
61 | #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) | 61 | #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) |
62 | #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) | 62 | #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) |
@@ -398,8 +398,11 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args | |||
398 | p = xdr_encode_fhandle(p, args->fromfh); | 398 | p = xdr_encode_fhandle(p, args->fromfh); |
399 | p = xdr_encode_array(p, args->fromname, args->fromlen); | 399 | p = xdr_encode_array(p, args->fromname, args->fromlen); |
400 | p = xdr_encode_sattr(p, args->sattr); | 400 | p = xdr_encode_sattr(p, args->sattr); |
401 | p = xdr_encode_array(p, args->topath, args->tolen); | 401 | *p++ = htonl(args->pathlen); |
402 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | 402 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); |
403 | |||
404 | /* Copy the page */ | ||
405 | xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen); | ||
403 | return 0; | 406 | return 0; |
404 | } | 407 | } |
405 | 408 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 9a102860df37..61095fe4b5ca 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -43,55 +43,6 @@ enum nfs4_client_state { | |||
43 | }; | 43 | }; |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * The nfs4_client identifies our client state to the server. | ||
47 | */ | ||
48 | struct nfs4_client { | ||
49 | struct list_head cl_servers; /* Global list of servers */ | ||
50 | struct in_addr cl_addr; /* Server identifier */ | ||
51 | u64 cl_clientid; /* constant */ | ||
52 | nfs4_verifier cl_confirm; | ||
53 | unsigned long cl_state; | ||
54 | |||
55 | u32 cl_lockowner_id; | ||
56 | |||
57 | /* | ||
58 | * The following rwsem ensures exclusive access to the server | ||
59 | * while we recover the state following a lease expiration. | ||
60 | */ | ||
61 | struct rw_semaphore cl_sem; | ||
62 | |||
63 | struct list_head cl_delegations; | ||
64 | struct list_head cl_state_owners; | ||
65 | struct list_head cl_unused; | ||
66 | int cl_nunused; | ||
67 | spinlock_t cl_lock; | ||
68 | atomic_t cl_count; | ||
69 | |||
70 | struct rpc_clnt * cl_rpcclient; | ||
71 | |||
72 | struct list_head cl_superblocks; /* List of nfs_server structs */ | ||
73 | |||
74 | unsigned long cl_lease_time; | ||
75 | unsigned long cl_last_renewal; | ||
76 | struct work_struct cl_renewd; | ||
77 | struct work_struct cl_recoverd; | ||
78 | |||
79 | struct rpc_wait_queue cl_rpcwaitq; | ||
80 | |||
81 | /* used for the setclientid verifier */ | ||
82 | struct timespec cl_boot_time; | ||
83 | |||
84 | /* idmapper */ | ||
85 | struct idmap * cl_idmap; | ||
86 | |||
87 | /* Our own IP address, as a null-terminated string. | ||
88 | * This is used to generate the clientid, and the callback address. | ||
89 | */ | ||
90 | char cl_ipaddr[16]; | ||
91 | unsigned char cl_id_uniquifier; | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * struct rpc_sequence ensures that RPC calls are sent in the exact | 46 | * struct rpc_sequence ensures that RPC calls are sent in the exact |
96 | * order that they appear on the list. | 47 | * order that they appear on the list. |
97 | */ | 48 | */ |
@@ -127,7 +78,7 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status | |||
127 | struct nfs4_state_owner { | 78 | struct nfs4_state_owner { |
128 | spinlock_t so_lock; | 79 | spinlock_t so_lock; |
129 | struct list_head so_list; /* per-clientid list of state_owners */ | 80 | struct list_head so_list; /* per-clientid list of state_owners */ |
130 | struct nfs4_client *so_client; | 81 | struct nfs_client *so_client; |
131 | u32 so_id; /* 32-bit identifier, unique */ | 82 | u32 so_id; /* 32-bit identifier, unique */ |
132 | atomic_t so_count; | 83 | atomic_t so_count; |
133 | 84 | ||
@@ -210,10 +161,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | |||
210 | 161 | ||
211 | /* nfs4proc.c */ | 162 | /* nfs4proc.c */ |
212 | extern int nfs4_map_errors(int err); | 163 | extern int nfs4_map_errors(int err); |
213 | extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short, struct rpc_cred *); | 164 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); |
214 | extern int nfs4_proc_setclientid_confirm(struct nfs4_client *, struct rpc_cred *); | 165 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
215 | extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *); | 166 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
216 | extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *); | 167 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
217 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); | 168 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); |
218 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 169 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
219 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 170 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -231,19 +182,14 @@ extern const u32 nfs4_fsinfo_bitmap[2]; | |||
231 | extern const u32 nfs4_fs_locations_bitmap[2]; | 182 | extern const u32 nfs4_fs_locations_bitmap[2]; |
232 | 183 | ||
233 | /* nfs4renewd.c */ | 184 | /* nfs4renewd.c */ |
234 | extern void nfs4_schedule_state_renewal(struct nfs4_client *); | 185 | extern void nfs4_schedule_state_renewal(struct nfs_client *); |
235 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); | 186 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); |
236 | extern void nfs4_kill_renewd(struct nfs4_client *); | 187 | extern void nfs4_kill_renewd(struct nfs_client *); |
237 | extern void nfs4_renew_state(void *); | 188 | extern void nfs4_renew_state(void *); |
238 | 189 | ||
239 | /* nfs4state.c */ | 190 | /* nfs4state.c */ |
240 | extern void init_nfsv4_state(struct nfs_server *); | 191 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); |
241 | extern void destroy_nfsv4_state(struct nfs_server *); | 192 | extern u32 nfs4_alloc_lockowner_id(struct nfs_client *); |
242 | extern struct nfs4_client *nfs4_get_client(struct in_addr *); | ||
243 | extern void nfs4_put_client(struct nfs4_client *clp); | ||
244 | extern struct nfs4_client *nfs4_find_client(struct in_addr *); | ||
245 | struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp); | ||
246 | extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); | ||
247 | 193 | ||
248 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 194 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
249 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 195 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
@@ -252,7 +198,7 @@ extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state | |||
252 | extern void nfs4_put_open_state(struct nfs4_state *); | 198 | extern void nfs4_put_open_state(struct nfs4_state *); |
253 | extern void nfs4_close_state(struct nfs4_state *, mode_t); | 199 | extern void nfs4_close_state(struct nfs4_state *, mode_t); |
254 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); | 200 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); |
255 | extern void nfs4_schedule_state_recovery(struct nfs4_client *); | 201 | extern void nfs4_schedule_state_recovery(struct nfs_client *); |
256 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 202 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
257 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 203 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
258 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 204 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
@@ -276,10 +222,6 @@ extern struct svc_version nfs4_callback_version1; | |||
276 | 222 | ||
277 | #else | 223 | #else |
278 | 224 | ||
279 | #define init_nfsv4_state(server) do { } while (0) | ||
280 | #define destroy_nfsv4_state(server) do { } while (0) | ||
281 | #define nfs4_put_state_owner(inode, owner) do { } while (0) | ||
282 | #define nfs4_put_open_state(state) do { } while (0) | ||
283 | #define nfs4_close_state(a, b) do { } while (0) | 225 | #define nfs4_close_state(a, b) do { } while (0) |
284 | 226 | ||
285 | #endif /* CONFIG_NFS_V4 */ | 227 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index ea38d27b74e6..24e47f3bbd17 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * linux/fs/nfs/nfs4namespace.c | 2 | * linux/fs/nfs/nfs4namespace.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> | 4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> |
5 | * - Modified by David Howells <dhowells@redhat.com> | ||
5 | * | 6 | * |
6 | * NFSv4 namespace | 7 | * NFSv4 namespace |
7 | */ | 8 | */ |
@@ -23,7 +24,7 @@ | |||
23 | /* | 24 | /* |
24 | * Check if fs_root is valid | 25 | * Check if fs_root is valid |
25 | */ | 26 | */ |
26 | static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname, | 27 | static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, |
27 | char *buffer, ssize_t buflen) | 28 | char *buffer, ssize_t buflen) |
28 | { | 29 | { |
29 | char *end = buffer + buflen; | 30 | char *end = buffer + buflen; |
@@ -34,7 +35,7 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname, | |||
34 | 35 | ||
35 | n = pathname->ncomponents; | 36 | n = pathname->ncomponents; |
36 | while (--n >= 0) { | 37 | while (--n >= 0) { |
37 | struct nfs4_string *component = &pathname->components[n]; | 38 | const struct nfs4_string *component = &pathname->components[n]; |
38 | buflen -= component->len + 1; | 39 | buflen -= component->len + 1; |
39 | if (buflen < 0) | 40 | if (buflen < 0) |
40 | goto Elong; | 41 | goto Elong; |
@@ -47,6 +48,68 @@ Elong: | |||
47 | return ERR_PTR(-ENAMETOOLONG); | 48 | return ERR_PTR(-ENAMETOOLONG); |
48 | } | 49 | } |
49 | 50 | ||
51 | /* | ||
52 | * Determine the mount path as a string | ||
53 | */ | ||
54 | static char *nfs4_path(const struct vfsmount *mnt_parent, | ||
55 | const struct dentry *dentry, | ||
56 | char *buffer, ssize_t buflen) | ||
57 | { | ||
58 | const char *srvpath; | ||
59 | |||
60 | srvpath = strchr(mnt_parent->mnt_devname, ':'); | ||
61 | if (srvpath) | ||
62 | srvpath++; | ||
63 | else | ||
64 | srvpath = mnt_parent->mnt_devname; | ||
65 | |||
66 | return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we | ||
71 | * believe to be the server path to this dentry | ||
72 | */ | ||
73 | static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, | ||
74 | const struct dentry *dentry, | ||
75 | const struct nfs4_fs_locations *locations, | ||
76 | char *page, char *page2) | ||
77 | { | ||
78 | const char *path, *fs_path; | ||
79 | |||
80 | path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE); | ||
81 | if (IS_ERR(path)) | ||
82 | return PTR_ERR(path); | ||
83 | |||
84 | fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); | ||
85 | if (IS_ERR(fs_path)) | ||
86 | return PTR_ERR(fs_path); | ||
87 | |||
88 | if (strncmp(path, fs_path, strlen(fs_path)) != 0) { | ||
89 | dprintk("%s: path %s does not begin with fsroot %s\n", | ||
90 | __FUNCTION__, path, fs_path); | ||
91 | return -ENOENT; | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Check if the string represents a "valid" IPv4 address | ||
99 | */ | ||
100 | static inline int valid_ipaddr4(const char *buf) | ||
101 | { | ||
102 | int rc, count, in[4]; | ||
103 | |||
104 | rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); | ||
105 | if (rc != 4) | ||
106 | return -EINVAL; | ||
107 | for (count = 0; count < 4; count++) { | ||
108 | if (in[count] > 255) | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
50 | 113 | ||
51 | /** | 114 | /** |
52 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error | 115 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
@@ -60,7 +123,7 @@ Elong: | |||
60 | */ | 123 | */ |
61 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | 124 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, |
62 | const struct dentry *dentry, | 125 | const struct dentry *dentry, |
63 | struct nfs4_fs_locations *locations) | 126 | const struct nfs4_fs_locations *locations) |
64 | { | 127 | { |
65 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 128 | struct vfsmount *mnt = ERR_PTR(-ENOENT); |
66 | struct nfs_clone_mount mountdata = { | 129 | struct nfs_clone_mount mountdata = { |
@@ -68,10 +131,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
68 | .dentry = dentry, | 131 | .dentry = dentry, |
69 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | 132 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, |
70 | }; | 133 | }; |
71 | char *page, *page2; | 134 | char *page = NULL, *page2 = NULL; |
72 | char *path, *fs_path; | ||
73 | char *devname; | 135 | char *devname; |
74 | int loc, s; | 136 | int loc, s, error; |
75 | 137 | ||
76 | if (locations == NULL || locations->nlocations <= 0) | 138 | if (locations == NULL || locations->nlocations <= 0) |
77 | goto out; | 139 | goto out; |
@@ -79,36 +141,30 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
79 | dprintk("%s: referral at %s/%s\n", __FUNCTION__, | 141 | dprintk("%s: referral at %s/%s\n", __FUNCTION__, |
80 | dentry->d_parent->d_name.name, dentry->d_name.name); | 142 | dentry->d_parent->d_name.name, dentry->d_name.name); |
81 | 143 | ||
82 | /* Ensure fs path is a prefix of current dentry path */ | ||
83 | page = (char *) __get_free_page(GFP_USER); | 144 | page = (char *) __get_free_page(GFP_USER); |
84 | if (page == NULL) | 145 | if (!page) |
85 | goto out; | 146 | goto out; |
147 | |||
86 | page2 = (char *) __get_free_page(GFP_USER); | 148 | page2 = (char *) __get_free_page(GFP_USER); |
87 | if (page2 == NULL) | 149 | if (!page2) |
88 | goto out; | 150 | goto out; |
89 | 151 | ||
90 | path = nfs4_path(dentry, page, PAGE_SIZE); | 152 | /* Ensure fs path is a prefix of current dentry path */ |
91 | if (IS_ERR(path)) | 153 | error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2); |
92 | goto out_free; | 154 | if (error < 0) { |
93 | 155 | mnt = ERR_PTR(error); | |
94 | fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); | 156 | goto out; |
95 | if (IS_ERR(fs_path)) | ||
96 | goto out_free; | ||
97 | |||
98 | if (strncmp(path, fs_path, strlen(fs_path)) != 0) { | ||
99 | dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path); | ||
100 | goto out_free; | ||
101 | } | 157 | } |
102 | 158 | ||
103 | devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); | 159 | devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); |
104 | if (IS_ERR(devname)) { | 160 | if (IS_ERR(devname)) { |
105 | mnt = (struct vfsmount *)devname; | 161 | mnt = (struct vfsmount *)devname; |
106 | goto out_free; | 162 | goto out; |
107 | } | 163 | } |
108 | 164 | ||
109 | loc = 0; | 165 | loc = 0; |
110 | while (loc < locations->nlocations && IS_ERR(mnt)) { | 166 | while (loc < locations->nlocations && IS_ERR(mnt)) { |
111 | struct nfs4_fs_location *location = &locations->locations[loc]; | 167 | const struct nfs4_fs_location *location = &locations->locations[loc]; |
112 | char *mnt_path; | 168 | char *mnt_path; |
113 | 169 | ||
114 | if (location == NULL || location->nservers <= 0 || | 170 | if (location == NULL || location->nservers <= 0 || |
@@ -140,7 +196,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
140 | addr.sin_port = htons(NFS_PORT); | 196 | addr.sin_port = htons(NFS_PORT); |
141 | mountdata.addr = &addr; | 197 | mountdata.addr = &addr; |
142 | 198 | ||
143 | mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata); | 199 | mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata); |
144 | if (!IS_ERR(mnt)) { | 200 | if (!IS_ERR(mnt)) { |
145 | break; | 201 | break; |
146 | } | 202 | } |
@@ -149,10 +205,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
149 | loc++; | 205 | loc++; |
150 | } | 206 | } |
151 | 207 | ||
152 | out_free: | ||
153 | free_page((unsigned long)page); | ||
154 | free_page((unsigned long)page2); | ||
155 | out: | 208 | out: |
209 | free_page((unsigned long) page); | ||
210 | free_page((unsigned long) page2); | ||
156 | dprintk("%s: done\n", __FUNCTION__); | 211 | dprintk("%s: done\n", __FUNCTION__); |
157 | return mnt; | 212 | return mnt; |
158 | } | 213 | } |
@@ -165,7 +220,7 @@ out: | |||
165 | */ | 220 | */ |
166 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | 221 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) |
167 | { | 222 | { |
168 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 223 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
169 | struct dentry *parent; | 224 | struct dentry *parent; |
170 | struct nfs4_fs_locations *fs_locations = NULL; | 225 | struct nfs4_fs_locations *fs_locations = NULL; |
171 | struct page *page; | 226 | struct page *page; |
@@ -183,11 +238,16 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr | |||
183 | goto out_free; | 238 | goto out_free; |
184 | 239 | ||
185 | /* Get locations */ | 240 | /* Get locations */ |
241 | mnt = ERR_PTR(-ENOENT); | ||
242 | |||
186 | parent = dget_parent(dentry); | 243 | parent = dget_parent(dentry); |
187 | dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name); | 244 | dprintk("%s: getting locations for %s/%s\n", |
245 | __FUNCTION__, parent->d_name.name, dentry->d_name.name); | ||
246 | |||
188 | err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); | 247 | err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); |
189 | dput(parent); | 248 | dput(parent); |
190 | if (err != 0 || fs_locations->nlocations <= 0 || | 249 | if (err != 0 || |
250 | fs_locations->nlocations <= 0 || | ||
191 | fs_locations->fs_path.ncomponents <= 0) | 251 | fs_locations->fs_path.ncomponents <= 0) |
192 | goto out_free; | 252 | goto out_free; |
193 | 253 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b14145b7b87f..47c7e6e3910d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -55,7 +55,7 @@ | |||
55 | 55 | ||
56 | #define NFSDBG_FACILITY NFSDBG_PROC | 56 | #define NFSDBG_FACILITY NFSDBG_PROC |
57 | 57 | ||
58 | #define NFS4_POLL_RETRY_MIN (1*HZ) | 58 | #define NFS4_POLL_RETRY_MIN (HZ/10) |
59 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 59 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
60 | 60 | ||
61 | struct nfs4_opendata; | 61 | struct nfs4_opendata; |
@@ -64,7 +64,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf | |||
64 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 64 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
65 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 65 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp); | 67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); |
68 | 68 | ||
69 | /* Prevent leaks of NFSv4 errors into userland */ | 69 | /* Prevent leaks of NFSv4 errors into userland */ |
70 | int nfs4_map_errors(int err) | 70 | int nfs4_map_errors(int err) |
@@ -195,7 +195,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
195 | 195 | ||
196 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | 196 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) |
197 | { | 197 | { |
198 | struct nfs4_client *clp = server->nfs4_state; | 198 | struct nfs_client *clp = server->nfs_client; |
199 | spin_lock(&clp->cl_lock); | 199 | spin_lock(&clp->cl_lock); |
200 | if (time_before(clp->cl_last_renewal,timestamp)) | 200 | if (time_before(clp->cl_last_renewal,timestamp)) |
201 | clp->cl_last_renewal = timestamp; | 201 | clp->cl_last_renewal = timestamp; |
@@ -252,7 +252,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
252 | atomic_inc(&sp->so_count); | 252 | atomic_inc(&sp->so_count); |
253 | p->o_arg.fh = NFS_FH(dir); | 253 | p->o_arg.fh = NFS_FH(dir); |
254 | p->o_arg.open_flags = flags, | 254 | p->o_arg.open_flags = flags, |
255 | p->o_arg.clientid = server->nfs4_state->cl_clientid; | 255 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
256 | p->o_arg.id = sp->so_id; | 256 | p->o_arg.id = sp->so_id; |
257 | p->o_arg.name = &dentry->d_name; | 257 | p->o_arg.name = &dentry->d_name; |
258 | p->o_arg.server = server; | 258 | p->o_arg.server = server; |
@@ -550,7 +550,7 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |||
550 | case -NFS4ERR_STALE_STATEID: | 550 | case -NFS4ERR_STALE_STATEID: |
551 | case -NFS4ERR_EXPIRED: | 551 | case -NFS4ERR_EXPIRED: |
552 | /* Don't recall a delegation if it was lost */ | 552 | /* Don't recall a delegation if it was lost */ |
553 | nfs4_schedule_state_recovery(server->nfs4_state); | 553 | nfs4_schedule_state_recovery(server->nfs_client); |
554 | return err; | 554 | return err; |
555 | } | 555 | } |
556 | err = nfs4_handle_exception(server, err, &exception); | 556 | err = nfs4_handle_exception(server, err, &exception); |
@@ -758,7 +758,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
758 | } | 758 | } |
759 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 759 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
760 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 760 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) |
761 | return server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); | 761 | return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); |
762 | return 0; | 762 | return 0; |
763 | } | 763 | } |
764 | 764 | ||
@@ -792,11 +792,18 @@ out: | |||
792 | 792 | ||
793 | int nfs4_recover_expired_lease(struct nfs_server *server) | 793 | int nfs4_recover_expired_lease(struct nfs_server *server) |
794 | { | 794 | { |
795 | struct nfs4_client *clp = server->nfs4_state; | 795 | struct nfs_client *clp = server->nfs_client; |
796 | int ret; | ||
796 | 797 | ||
797 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 798 | for (;;) { |
799 | ret = nfs4_wait_clnt_recover(server->client, clp); | ||
800 | if (ret != 0) | ||
801 | return ret; | ||
802 | if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | ||
803 | break; | ||
798 | nfs4_schedule_state_recovery(clp); | 804 | nfs4_schedule_state_recovery(clp); |
799 | return nfs4_wait_clnt_recover(server->client, clp); | 805 | } |
806 | return 0; | ||
800 | } | 807 | } |
801 | 808 | ||
802 | /* | 809 | /* |
@@ -867,7 +874,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
867 | { | 874 | { |
868 | struct nfs_delegation *delegation; | 875 | struct nfs_delegation *delegation; |
869 | struct nfs_server *server = NFS_SERVER(inode); | 876 | struct nfs_server *server = NFS_SERVER(inode); |
870 | struct nfs4_client *clp = server->nfs4_state; | 877 | struct nfs_client *clp = server->nfs_client; |
871 | struct nfs_inode *nfsi = NFS_I(inode); | 878 | struct nfs_inode *nfsi = NFS_I(inode); |
872 | struct nfs4_state_owner *sp = NULL; | 879 | struct nfs4_state_owner *sp = NULL; |
873 | struct nfs4_state *state = NULL; | 880 | struct nfs4_state *state = NULL; |
@@ -953,7 +960,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
953 | struct nfs4_state_owner *sp; | 960 | struct nfs4_state_owner *sp; |
954 | struct nfs4_state *state = NULL; | 961 | struct nfs4_state *state = NULL; |
955 | struct nfs_server *server = NFS_SERVER(dir); | 962 | struct nfs_server *server = NFS_SERVER(dir); |
956 | struct nfs4_client *clp = server->nfs4_state; | 963 | struct nfs_client *clp = server->nfs_client; |
957 | struct nfs4_opendata *opendata; | 964 | struct nfs4_opendata *opendata; |
958 | int status; | 965 | int status; |
959 | 966 | ||
@@ -1133,7 +1140,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1133 | break; | 1140 | break; |
1134 | case -NFS4ERR_STALE_STATEID: | 1141 | case -NFS4ERR_STALE_STATEID: |
1135 | case -NFS4ERR_EXPIRED: | 1142 | case -NFS4ERR_EXPIRED: |
1136 | nfs4_schedule_state_recovery(server->nfs4_state); | 1143 | nfs4_schedule_state_recovery(server->nfs_client); |
1137 | break; | 1144 | break; |
1138 | default: | 1145 | default: |
1139 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 1146 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { |
@@ -1268,7 +1275,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1268 | BUG_ON(nd->intent.open.flags & O_CREAT); | 1275 | BUG_ON(nd->intent.open.flags & O_CREAT); |
1269 | } | 1276 | } |
1270 | 1277 | ||
1271 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1278 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1272 | if (IS_ERR(cred)) | 1279 | if (IS_ERR(cred)) |
1273 | return (struct dentry *)cred; | 1280 | return (struct dentry *)cred; |
1274 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); | 1281 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); |
@@ -1291,7 +1298,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1291 | struct rpc_cred *cred; | 1298 | struct rpc_cred *cred; |
1292 | struct nfs4_state *state; | 1299 | struct nfs4_state *state; |
1293 | 1300 | ||
1294 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1301 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1295 | if (IS_ERR(cred)) | 1302 | if (IS_ERR(cred)) |
1296 | return PTR_ERR(cred); | 1303 | return PTR_ERR(cred); |
1297 | state = nfs4_open_delegated(dentry->d_inode, openflags, cred); | 1304 | state = nfs4_open_delegated(dentry->d_inode, openflags, cred); |
@@ -1393,70 +1400,19 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1393 | return err; | 1400 | return err; |
1394 | } | 1401 | } |
1395 | 1402 | ||
1403 | /* | ||
1404 | * get the file handle for the "/" directory on the server | ||
1405 | */ | ||
1396 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 1406 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
1397 | struct nfs_fsinfo *info) | 1407 | struct nfs_fsinfo *info) |
1398 | { | 1408 | { |
1399 | struct nfs_fattr * fattr = info->fattr; | ||
1400 | unsigned char * p; | ||
1401 | struct qstr q; | ||
1402 | struct nfs4_lookup_arg args = { | ||
1403 | .dir_fh = fhandle, | ||
1404 | .name = &q, | ||
1405 | .bitmask = nfs4_fattr_bitmap, | ||
1406 | }; | ||
1407 | struct nfs4_lookup_res res = { | ||
1408 | .server = server, | ||
1409 | .fattr = fattr, | ||
1410 | .fh = fhandle, | ||
1411 | }; | ||
1412 | struct rpc_message msg = { | ||
1413 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], | ||
1414 | .rpc_argp = &args, | ||
1415 | .rpc_resp = &res, | ||
1416 | }; | ||
1417 | int status; | 1409 | int status; |
1418 | 1410 | ||
1419 | /* | ||
1420 | * Now we do a separate LOOKUP for each component of the mount path. | ||
1421 | * The LOOKUPs are done separately so that we can conveniently | ||
1422 | * catch an ERR_WRONGSEC if it occurs along the way... | ||
1423 | */ | ||
1424 | status = nfs4_lookup_root(server, fhandle, info); | 1411 | status = nfs4_lookup_root(server, fhandle, info); |
1425 | if (status) | ||
1426 | goto out; | ||
1427 | |||
1428 | p = server->mnt_path; | ||
1429 | for (;;) { | ||
1430 | struct nfs4_exception exception = { }; | ||
1431 | |||
1432 | while (*p == '/') | ||
1433 | p++; | ||
1434 | if (!*p) | ||
1435 | break; | ||
1436 | q.name = p; | ||
1437 | while (*p && (*p != '/')) | ||
1438 | p++; | ||
1439 | q.len = p - q.name; | ||
1440 | |||
1441 | do { | ||
1442 | nfs_fattr_init(fattr); | ||
1443 | status = nfs4_handle_exception(server, | ||
1444 | rpc_call_sync(server->client, &msg, 0), | ||
1445 | &exception); | ||
1446 | } while (exception.retry); | ||
1447 | if (status == 0) | ||
1448 | continue; | ||
1449 | if (status == -ENOENT) { | ||
1450 | printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path); | ||
1451 | printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n"); | ||
1452 | } | ||
1453 | break; | ||
1454 | } | ||
1455 | if (status == 0) | 1412 | if (status == 0) |
1456 | status = nfs4_server_capabilities(server, fhandle); | 1413 | status = nfs4_server_capabilities(server, fhandle); |
1457 | if (status == 0) | 1414 | if (status == 0) |
1458 | status = nfs4_do_fsinfo(server, fhandle, info); | 1415 | status = nfs4_do_fsinfo(server, fhandle, info); |
1459 | out: | ||
1460 | return nfs4_map_errors(status); | 1416 | return nfs4_map_errors(status); |
1461 | } | 1417 | } |
1462 | 1418 | ||
@@ -1565,7 +1521,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1565 | 1521 | ||
1566 | nfs_fattr_init(fattr); | 1522 | nfs_fattr_init(fattr); |
1567 | 1523 | ||
1568 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1524 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); |
1569 | if (IS_ERR(cred)) | 1525 | if (IS_ERR(cred)) |
1570 | return PTR_ERR(cred); | 1526 | return PTR_ERR(cred); |
1571 | 1527 | ||
@@ -1583,6 +1539,52 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1583 | return status; | 1539 | return status; |
1584 | } | 1540 | } |
1585 | 1541 | ||
1542 | static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | ||
1543 | struct qstr *name, struct nfs_fh *fhandle, | ||
1544 | struct nfs_fattr *fattr) | ||
1545 | { | ||
1546 | int status; | ||
1547 | struct nfs4_lookup_arg args = { | ||
1548 | .bitmask = server->attr_bitmask, | ||
1549 | .dir_fh = dirfh, | ||
1550 | .name = name, | ||
1551 | }; | ||
1552 | struct nfs4_lookup_res res = { | ||
1553 | .server = server, | ||
1554 | .fattr = fattr, | ||
1555 | .fh = fhandle, | ||
1556 | }; | ||
1557 | struct rpc_message msg = { | ||
1558 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], | ||
1559 | .rpc_argp = &args, | ||
1560 | .rpc_resp = &res, | ||
1561 | }; | ||
1562 | |||
1563 | nfs_fattr_init(fattr); | ||
1564 | |||
1565 | dprintk("NFS call lookupfh %s\n", name->name); | ||
1566 | status = rpc_call_sync(server->client, &msg, 0); | ||
1567 | dprintk("NFS reply lookupfh: %d\n", status); | ||
1568 | if (status == -NFS4ERR_MOVED) | ||
1569 | status = -EREMOTE; | ||
1570 | return status; | ||
1571 | } | ||
1572 | |||
1573 | static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | ||
1574 | struct qstr *name, struct nfs_fh *fhandle, | ||
1575 | struct nfs_fattr *fattr) | ||
1576 | { | ||
1577 | struct nfs4_exception exception = { }; | ||
1578 | int err; | ||
1579 | do { | ||
1580 | err = nfs4_handle_exception(server, | ||
1581 | _nfs4_proc_lookupfh(server, dirfh, name, | ||
1582 | fhandle, fattr), | ||
1583 | &exception); | ||
1584 | } while (exception.retry); | ||
1585 | return err; | ||
1586 | } | ||
1587 | |||
1586 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | 1588 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, |
1587 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 1589 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
1588 | { | 1590 | { |
@@ -1881,7 +1883,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1881 | struct rpc_cred *cred; | 1883 | struct rpc_cred *cred; |
1882 | int status = 0; | 1884 | int status = 0; |
1883 | 1885 | ||
1884 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1886 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1885 | if (IS_ERR(cred)) { | 1887 | if (IS_ERR(cred)) { |
1886 | status = PTR_ERR(cred); | 1888 | status = PTR_ERR(cred); |
1887 | goto out; | 1889 | goto out; |
@@ -2089,24 +2091,24 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n | |||
2089 | return err; | 2091 | return err; |
2090 | } | 2092 | } |
2091 | 2093 | ||
2092 | static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | 2094 | static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, |
2093 | struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, | 2095 | struct page *page, unsigned int len, struct iattr *sattr) |
2094 | struct nfs_fattr *fattr) | ||
2095 | { | 2096 | { |
2096 | struct nfs_server *server = NFS_SERVER(dir); | 2097 | struct nfs_server *server = NFS_SERVER(dir); |
2097 | struct nfs_fattr dir_fattr; | 2098 | struct nfs_fh fhandle; |
2099 | struct nfs_fattr fattr, dir_fattr; | ||
2098 | struct nfs4_create_arg arg = { | 2100 | struct nfs4_create_arg arg = { |
2099 | .dir_fh = NFS_FH(dir), | 2101 | .dir_fh = NFS_FH(dir), |
2100 | .server = server, | 2102 | .server = server, |
2101 | .name = name, | 2103 | .name = &dentry->d_name, |
2102 | .attrs = sattr, | 2104 | .attrs = sattr, |
2103 | .ftype = NF4LNK, | 2105 | .ftype = NF4LNK, |
2104 | .bitmask = server->attr_bitmask, | 2106 | .bitmask = server->attr_bitmask, |
2105 | }; | 2107 | }; |
2106 | struct nfs4_create_res res = { | 2108 | struct nfs4_create_res res = { |
2107 | .server = server, | 2109 | .server = server, |
2108 | .fh = fhandle, | 2110 | .fh = &fhandle, |
2109 | .fattr = fattr, | 2111 | .fattr = &fattr, |
2110 | .dir_fattr = &dir_fattr, | 2112 | .dir_fattr = &dir_fattr, |
2111 | }; | 2113 | }; |
2112 | struct rpc_message msg = { | 2114 | struct rpc_message msg = { |
@@ -2116,29 +2118,32 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | |||
2116 | }; | 2118 | }; |
2117 | int status; | 2119 | int status; |
2118 | 2120 | ||
2119 | if (path->len > NFS4_MAXPATHLEN) | 2121 | if (len > NFS4_MAXPATHLEN) |
2120 | return -ENAMETOOLONG; | 2122 | return -ENAMETOOLONG; |
2121 | arg.u.symlink = path; | 2123 | |
2122 | nfs_fattr_init(fattr); | 2124 | arg.u.symlink.pages = &page; |
2125 | arg.u.symlink.len = len; | ||
2126 | nfs_fattr_init(&fattr); | ||
2123 | nfs_fattr_init(&dir_fattr); | 2127 | nfs_fattr_init(&dir_fattr); |
2124 | 2128 | ||
2125 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2129 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
2126 | if (!status) | 2130 | if (!status) { |
2127 | update_changeattr(dir, &res.dir_cinfo); | 2131 | update_changeattr(dir, &res.dir_cinfo); |
2128 | nfs_post_op_update_inode(dir, res.dir_fattr); | 2132 | nfs_post_op_update_inode(dir, res.dir_fattr); |
2133 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
2134 | } | ||
2129 | return status; | 2135 | return status; |
2130 | } | 2136 | } |
2131 | 2137 | ||
2132 | static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, | 2138 | static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, |
2133 | struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, | 2139 | struct page *page, unsigned int len, struct iattr *sattr) |
2134 | struct nfs_fattr *fattr) | ||
2135 | { | 2140 | { |
2136 | struct nfs4_exception exception = { }; | 2141 | struct nfs4_exception exception = { }; |
2137 | int err; | 2142 | int err; |
2138 | do { | 2143 | do { |
2139 | err = nfs4_handle_exception(NFS_SERVER(dir), | 2144 | err = nfs4_handle_exception(NFS_SERVER(dir), |
2140 | _nfs4_proc_symlink(dir, name, path, sattr, | 2145 | _nfs4_proc_symlink(dir, dentry, page, |
2141 | fhandle, fattr), | 2146 | len, sattr), |
2142 | &exception); | 2147 | &exception); |
2143 | } while (exception.retry); | 2148 | } while (exception.retry); |
2144 | return err; | 2149 | return err; |
@@ -2521,7 +2526,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | |||
2521 | */ | 2526 | */ |
2522 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 2527 | static void nfs4_renew_done(struct rpc_task *task, void *data) |
2523 | { | 2528 | { |
2524 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; | 2529 | struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp; |
2525 | unsigned long timestamp = (unsigned long)data; | 2530 | unsigned long timestamp = (unsigned long)data; |
2526 | 2531 | ||
2527 | if (task->tk_status < 0) { | 2532 | if (task->tk_status < 0) { |
@@ -2543,7 +2548,7 @@ static const struct rpc_call_ops nfs4_renew_ops = { | |||
2543 | .rpc_call_done = nfs4_renew_done, | 2548 | .rpc_call_done = nfs4_renew_done, |
2544 | }; | 2549 | }; |
2545 | 2550 | ||
2546 | int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred) | 2551 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) |
2547 | { | 2552 | { |
2548 | struct rpc_message msg = { | 2553 | struct rpc_message msg = { |
2549 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2554 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
@@ -2555,7 +2560,7 @@ int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred) | |||
2555 | &nfs4_renew_ops, (void *)jiffies); | 2560 | &nfs4_renew_ops, (void *)jiffies); |
2556 | } | 2561 | } |
2557 | 2562 | ||
2558 | int nfs4_proc_renew(struct nfs4_client *clp, struct rpc_cred *cred) | 2563 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
2559 | { | 2564 | { |
2560 | struct rpc_message msg = { | 2565 | struct rpc_message msg = { |
2561 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2566 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
@@ -2770,7 +2775,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2770 | return -EOPNOTSUPP; | 2775 | return -EOPNOTSUPP; |
2771 | nfs_inode_return_delegation(inode); | 2776 | nfs_inode_return_delegation(inode); |
2772 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 2777 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
2773 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); | 2778 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
2774 | if (ret == 0) | 2779 | if (ret == 0) |
2775 | nfs4_write_cached_acl(inode, buf, buflen); | 2780 | nfs4_write_cached_acl(inode, buf, buflen); |
2776 | return ret; | 2781 | return ret; |
@@ -2791,7 +2796,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2791 | static int | 2796 | static int |
2792 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | 2797 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) |
2793 | { | 2798 | { |
2794 | struct nfs4_client *clp = server->nfs4_state; | 2799 | struct nfs_client *clp = server->nfs_client; |
2795 | 2800 | ||
2796 | if (!clp || task->tk_status >= 0) | 2801 | if (!clp || task->tk_status >= 0) |
2797 | return 0; | 2802 | return 0; |
@@ -2828,7 +2833,7 @@ static int nfs4_wait_bit_interruptible(void *word) | |||
2828 | return 0; | 2833 | return 0; |
2829 | } | 2834 | } |
2830 | 2835 | ||
2831 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) | 2836 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp) |
2832 | { | 2837 | { |
2833 | sigset_t oldset; | 2838 | sigset_t oldset; |
2834 | int res; | 2839 | int res; |
@@ -2871,7 +2876,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
2871 | */ | 2876 | */ |
2872 | int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 2877 | int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) |
2873 | { | 2878 | { |
2874 | struct nfs4_client *clp = server->nfs4_state; | 2879 | struct nfs_client *clp = server->nfs_client; |
2875 | int ret = errorcode; | 2880 | int ret = errorcode; |
2876 | 2881 | ||
2877 | exception->retry = 0; | 2882 | exception->retry = 0; |
@@ -2886,6 +2891,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
2886 | if (ret == 0) | 2891 | if (ret == 0) |
2887 | exception->retry = 1; | 2892 | exception->retry = 1; |
2888 | break; | 2893 | break; |
2894 | case -NFS4ERR_FILE_OPEN: | ||
2889 | case -NFS4ERR_GRACE: | 2895 | case -NFS4ERR_GRACE: |
2890 | case -NFS4ERR_DELAY: | 2896 | case -NFS4ERR_DELAY: |
2891 | ret = nfs4_delay(server->client, &exception->timeout); | 2897 | ret = nfs4_delay(server->client, &exception->timeout); |
@@ -2898,7 +2904,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
2898 | return nfs4_map_errors(ret); | 2904 | return nfs4_map_errors(ret); |
2899 | } | 2905 | } |
2900 | 2906 | ||
2901 | int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 2907 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2902 | { | 2908 | { |
2903 | nfs4_verifier sc_verifier; | 2909 | nfs4_verifier sc_verifier; |
2904 | struct nfs4_setclientid setclientid = { | 2910 | struct nfs4_setclientid setclientid = { |
@@ -2922,7 +2928,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2922 | for(;;) { | 2928 | for(;;) { |
2923 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 2929 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
2924 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", | 2930 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", |
2925 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr), | 2931 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.sin_addr), |
2926 | cred->cr_ops->cr_name, | 2932 | cred->cr_ops->cr_name, |
2927 | clp->cl_id_uniquifier); | 2933 | clp->cl_id_uniquifier); |
2928 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2934 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
@@ -2945,7 +2951,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2945 | return status; | 2951 | return status; |
2946 | } | 2952 | } |
2947 | 2953 | ||
2948 | static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | 2954 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) |
2949 | { | 2955 | { |
2950 | struct nfs_fsinfo fsinfo; | 2956 | struct nfs_fsinfo fsinfo; |
2951 | struct rpc_message msg = { | 2957 | struct rpc_message msg = { |
@@ -2969,7 +2975,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cr | |||
2969 | return status; | 2975 | return status; |
2970 | } | 2976 | } |
2971 | 2977 | ||
2972 | int nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | 2978 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) |
2973 | { | 2979 | { |
2974 | long timeout; | 2980 | long timeout; |
2975 | int err; | 2981 | int err; |
@@ -3077,7 +3083,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4 | |||
3077 | switch (err) { | 3083 | switch (err) { |
3078 | case -NFS4ERR_STALE_STATEID: | 3084 | case -NFS4ERR_STALE_STATEID: |
3079 | case -NFS4ERR_EXPIRED: | 3085 | case -NFS4ERR_EXPIRED: |
3080 | nfs4_schedule_state_recovery(server->nfs4_state); | 3086 | nfs4_schedule_state_recovery(server->nfs_client); |
3081 | case 0: | 3087 | case 0: |
3082 | return 0; | 3088 | return 0; |
3083 | } | 3089 | } |
@@ -3106,7 +3112,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3106 | { | 3112 | { |
3107 | struct inode *inode = state->inode; | 3113 | struct inode *inode = state->inode; |
3108 | struct nfs_server *server = NFS_SERVER(inode); | 3114 | struct nfs_server *server = NFS_SERVER(inode); |
3109 | struct nfs4_client *clp = server->nfs4_state; | 3115 | struct nfs_client *clp = server->nfs_client; |
3110 | struct nfs_lockt_args arg = { | 3116 | struct nfs_lockt_args arg = { |
3111 | .fh = NFS_FH(inode), | 3117 | .fh = NFS_FH(inode), |
3112 | .fl = request, | 3118 | .fl = request, |
@@ -3231,7 +3237,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3231 | break; | 3237 | break; |
3232 | case -NFS4ERR_STALE_STATEID: | 3238 | case -NFS4ERR_STALE_STATEID: |
3233 | case -NFS4ERR_EXPIRED: | 3239 | case -NFS4ERR_EXPIRED: |
3234 | nfs4_schedule_state_recovery(calldata->server->nfs4_state); | 3240 | nfs4_schedule_state_recovery(calldata->server->nfs_client); |
3235 | break; | 3241 | break; |
3236 | default: | 3242 | default: |
3237 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { | 3243 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { |
@@ -3343,7 +3349,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3343 | if (p->arg.lock_seqid == NULL) | 3349 | if (p->arg.lock_seqid == NULL) |
3344 | goto out_free; | 3350 | goto out_free; |
3345 | p->arg.lock_stateid = &lsp->ls_stateid; | 3351 | p->arg.lock_stateid = &lsp->ls_stateid; |
3346 | p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid; | 3352 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3347 | p->arg.lock_owner.id = lsp->ls_id; | 3353 | p->arg.lock_owner.id = lsp->ls_id; |
3348 | p->lsp = lsp; | 3354 | p->lsp = lsp; |
3349 | atomic_inc(&lsp->ls_count); | 3355 | atomic_inc(&lsp->ls_count); |
@@ -3513,7 +3519,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
3513 | 3519 | ||
3514 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 3520 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
3515 | { | 3521 | { |
3516 | struct nfs4_client *clp = state->owner->so_client; | 3522 | struct nfs_client *clp = state->owner->so_client; |
3517 | unsigned char fl_flags = request->fl_flags; | 3523 | unsigned char fl_flags = request->fl_flags; |
3518 | int status; | 3524 | int status; |
3519 | 3525 | ||
@@ -3715,7 +3721,7 @@ static struct inode_operations nfs4_file_inode_operations = { | |||
3715 | .listxattr = nfs4_listxattr, | 3721 | .listxattr = nfs4_listxattr, |
3716 | }; | 3722 | }; |
3717 | 3723 | ||
3718 | struct nfs_rpc_ops nfs_v4_clientops = { | 3724 | const struct nfs_rpc_ops nfs_v4_clientops = { |
3719 | .version = 4, /* protocol version */ | 3725 | .version = 4, /* protocol version */ |
3720 | .dentry_ops = &nfs4_dentry_operations, | 3726 | .dentry_ops = &nfs4_dentry_operations, |
3721 | .dir_inode_ops = &nfs4_dir_inode_operations, | 3727 | .dir_inode_ops = &nfs4_dir_inode_operations, |
@@ -3723,6 +3729,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
3723 | .getroot = nfs4_proc_get_root, | 3729 | .getroot = nfs4_proc_get_root, |
3724 | .getattr = nfs4_proc_getattr, | 3730 | .getattr = nfs4_proc_getattr, |
3725 | .setattr = nfs4_proc_setattr, | 3731 | .setattr = nfs4_proc_setattr, |
3732 | .lookupfh = nfs4_proc_lookupfh, | ||
3726 | .lookup = nfs4_proc_lookup, | 3733 | .lookup = nfs4_proc_lookup, |
3727 | .access = nfs4_proc_access, | 3734 | .access = nfs4_proc_access, |
3728 | .readlink = nfs4_proc_readlink, | 3735 | .readlink = nfs4_proc_readlink, |
@@ -3743,6 +3750,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
3743 | .statfs = nfs4_proc_statfs, | 3750 | .statfs = nfs4_proc_statfs, |
3744 | .fsinfo = nfs4_proc_fsinfo, | 3751 | .fsinfo = nfs4_proc_fsinfo, |
3745 | .pathconf = nfs4_proc_pathconf, | 3752 | .pathconf = nfs4_proc_pathconf, |
3753 | .set_capabilities = nfs4_server_capabilities, | ||
3746 | .decode_dirent = nfs4_decode_dirent, | 3754 | .decode_dirent = nfs4_decode_dirent, |
3747 | .read_setup = nfs4_proc_read_setup, | 3755 | .read_setup = nfs4_proc_read_setup, |
3748 | .read_done = nfs4_read_done, | 3756 | .read_done = nfs4_read_done, |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 5d764d8e6d8a..7b6df1852e75 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -61,7 +61,7 @@ | |||
61 | void | 61 | void |
62 | nfs4_renew_state(void *data) | 62 | nfs4_renew_state(void *data) |
63 | { | 63 | { |
64 | struct nfs4_client *clp = (struct nfs4_client *)data; | 64 | struct nfs_client *clp = (struct nfs_client *)data; |
65 | struct rpc_cred *cred; | 65 | struct rpc_cred *cred; |
66 | long lease, timeout; | 66 | long lease, timeout; |
67 | unsigned long last, now; | 67 | unsigned long last, now; |
@@ -108,7 +108,7 @@ out: | |||
108 | 108 | ||
109 | /* Must be called with clp->cl_sem locked for writes */ | 109 | /* Must be called with clp->cl_sem locked for writes */ |
110 | void | 110 | void |
111 | nfs4_schedule_state_renewal(struct nfs4_client *clp) | 111 | nfs4_schedule_state_renewal(struct nfs_client *clp) |
112 | { | 112 | { |
113 | long timeout; | 113 | long timeout; |
114 | 114 | ||
@@ -121,32 +121,20 @@ nfs4_schedule_state_renewal(struct nfs4_client *clp) | |||
121 | __FUNCTION__, (timeout + HZ - 1) / HZ); | 121 | __FUNCTION__, (timeout + HZ - 1) / HZ); |
122 | cancel_delayed_work(&clp->cl_renewd); | 122 | cancel_delayed_work(&clp->cl_renewd); |
123 | schedule_delayed_work(&clp->cl_renewd, timeout); | 123 | schedule_delayed_work(&clp->cl_renewd, timeout); |
124 | set_bit(NFS_CS_RENEWD, &clp->cl_res_state); | ||
124 | spin_unlock(&clp->cl_lock); | 125 | spin_unlock(&clp->cl_lock); |
125 | } | 126 | } |
126 | 127 | ||
127 | void | 128 | void |
128 | nfs4_renewd_prepare_shutdown(struct nfs_server *server) | 129 | nfs4_renewd_prepare_shutdown(struct nfs_server *server) |
129 | { | 130 | { |
130 | struct nfs4_client *clp = server->nfs4_state; | ||
131 | |||
132 | if (!clp) | ||
133 | return; | ||
134 | flush_scheduled_work(); | 131 | flush_scheduled_work(); |
135 | down_write(&clp->cl_sem); | ||
136 | if (!list_empty(&server->nfs4_siblings)) | ||
137 | list_del_init(&server->nfs4_siblings); | ||
138 | up_write(&clp->cl_sem); | ||
139 | } | 132 | } |
140 | 133 | ||
141 | /* Must be called with clp->cl_sem locked for writes */ | ||
142 | void | 134 | void |
143 | nfs4_kill_renewd(struct nfs4_client *clp) | 135 | nfs4_kill_renewd(struct nfs_client *clp) |
144 | { | 136 | { |
145 | down_read(&clp->cl_sem); | 137 | down_read(&clp->cl_sem); |
146 | if (!list_empty(&clp->cl_superblocks)) { | ||
147 | up_read(&clp->cl_sem); | ||
148 | return; | ||
149 | } | ||
150 | cancel_delayed_work(&clp->cl_renewd); | 138 | cancel_delayed_work(&clp->cl_renewd); |
151 | up_read(&clp->cl_sem); | 139 | up_read(&clp->cl_sem); |
152 | flush_scheduled_work(); | 140 | flush_scheduled_work(); |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 090a36b07a22..5fffbdfa971f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -50,149 +50,15 @@ | |||
50 | #include "nfs4_fs.h" | 50 | #include "nfs4_fs.h" |
51 | #include "callback.h" | 51 | #include "callback.h" |
52 | #include "delegation.h" | 52 | #include "delegation.h" |
53 | #include "internal.h" | ||
53 | 54 | ||
54 | #define OPENOWNER_POOL_SIZE 8 | 55 | #define OPENOWNER_POOL_SIZE 8 |
55 | 56 | ||
56 | const nfs4_stateid zero_stateid; | 57 | const nfs4_stateid zero_stateid; |
57 | 58 | ||
58 | static DEFINE_SPINLOCK(state_spinlock); | ||
59 | static LIST_HEAD(nfs4_clientid_list); | 59 | static LIST_HEAD(nfs4_clientid_list); |
60 | 60 | ||
61 | void | 61 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) |
62 | init_nfsv4_state(struct nfs_server *server) | ||
63 | { | ||
64 | server->nfs4_state = NULL; | ||
65 | INIT_LIST_HEAD(&server->nfs4_siblings); | ||
66 | } | ||
67 | |||
68 | void | ||
69 | destroy_nfsv4_state(struct nfs_server *server) | ||
70 | { | ||
71 | kfree(server->mnt_path); | ||
72 | server->mnt_path = NULL; | ||
73 | if (server->nfs4_state) { | ||
74 | nfs4_put_client(server->nfs4_state); | ||
75 | server->nfs4_state = NULL; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * nfs4_get_client(): returns an empty client structure | ||
81 | * nfs4_put_client(): drops reference to client structure | ||
82 | * | ||
83 | * Since these are allocated/deallocated very rarely, we don't | ||
84 | * bother putting them in a slab cache... | ||
85 | */ | ||
86 | static struct nfs4_client * | ||
87 | nfs4_alloc_client(struct in_addr *addr) | ||
88 | { | ||
89 | struct nfs4_client *clp; | ||
90 | |||
91 | if (nfs_callback_up() < 0) | ||
92 | return NULL; | ||
93 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) { | ||
94 | nfs_callback_down(); | ||
95 | return NULL; | ||
96 | } | ||
97 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | ||
98 | init_rwsem(&clp->cl_sem); | ||
99 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
100 | INIT_LIST_HEAD(&clp->cl_state_owners); | ||
101 | INIT_LIST_HEAD(&clp->cl_unused); | ||
102 | spin_lock_init(&clp->cl_lock); | ||
103 | atomic_set(&clp->cl_count, 1); | ||
104 | INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); | ||
105 | INIT_LIST_HEAD(&clp->cl_superblocks); | ||
106 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); | ||
107 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
108 | clp->cl_boot_time = CURRENT_TIME; | ||
109 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | ||
110 | return clp; | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | nfs4_free_client(struct nfs4_client *clp) | ||
115 | { | ||
116 | struct nfs4_state_owner *sp; | ||
117 | |||
118 | while (!list_empty(&clp->cl_unused)) { | ||
119 | sp = list_entry(clp->cl_unused.next, | ||
120 | struct nfs4_state_owner, | ||
121 | so_list); | ||
122 | list_del(&sp->so_list); | ||
123 | kfree(sp); | ||
124 | } | ||
125 | BUG_ON(!list_empty(&clp->cl_state_owners)); | ||
126 | nfs_idmap_delete(clp); | ||
127 | if (!IS_ERR(clp->cl_rpcclient)) | ||
128 | rpc_shutdown_client(clp->cl_rpcclient); | ||
129 | kfree(clp); | ||
130 | nfs_callback_down(); | ||
131 | } | ||
132 | |||
133 | static struct nfs4_client *__nfs4_find_client(struct in_addr *addr) | ||
134 | { | ||
135 | struct nfs4_client *clp; | ||
136 | list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) { | ||
137 | if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) { | ||
138 | atomic_inc(&clp->cl_count); | ||
139 | return clp; | ||
140 | } | ||
141 | } | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | struct nfs4_client *nfs4_find_client(struct in_addr *addr) | ||
146 | { | ||
147 | struct nfs4_client *clp; | ||
148 | spin_lock(&state_spinlock); | ||
149 | clp = __nfs4_find_client(addr); | ||
150 | spin_unlock(&state_spinlock); | ||
151 | return clp; | ||
152 | } | ||
153 | |||
154 | struct nfs4_client * | ||
155 | nfs4_get_client(struct in_addr *addr) | ||
156 | { | ||
157 | struct nfs4_client *clp, *new = NULL; | ||
158 | |||
159 | spin_lock(&state_spinlock); | ||
160 | for (;;) { | ||
161 | clp = __nfs4_find_client(addr); | ||
162 | if (clp != NULL) | ||
163 | break; | ||
164 | clp = new; | ||
165 | if (clp != NULL) { | ||
166 | list_add(&clp->cl_servers, &nfs4_clientid_list); | ||
167 | new = NULL; | ||
168 | break; | ||
169 | } | ||
170 | spin_unlock(&state_spinlock); | ||
171 | new = nfs4_alloc_client(addr); | ||
172 | spin_lock(&state_spinlock); | ||
173 | if (new == NULL) | ||
174 | break; | ||
175 | } | ||
176 | spin_unlock(&state_spinlock); | ||
177 | if (new) | ||
178 | nfs4_free_client(new); | ||
179 | return clp; | ||
180 | } | ||
181 | |||
182 | void | ||
183 | nfs4_put_client(struct nfs4_client *clp) | ||
184 | { | ||
185 | if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock)) | ||
186 | return; | ||
187 | list_del(&clp->cl_servers); | ||
188 | spin_unlock(&state_spinlock); | ||
189 | BUG_ON(!list_empty(&clp->cl_superblocks)); | ||
190 | rpc_wake_up(&clp->cl_rpcwaitq); | ||
191 | nfs4_kill_renewd(clp); | ||
192 | nfs4_free_client(clp); | ||
193 | } | ||
194 | |||
195 | static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred) | ||
196 | { | 62 | { |
197 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, | 63 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, |
198 | nfs_callback_tcpport, cred); | 64 | nfs_callback_tcpport, cred); |
@@ -204,13 +70,13 @@ static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred) | |||
204 | } | 70 | } |
205 | 71 | ||
206 | u32 | 72 | u32 |
207 | nfs4_alloc_lockowner_id(struct nfs4_client *clp) | 73 | nfs4_alloc_lockowner_id(struct nfs_client *clp) |
208 | { | 74 | { |
209 | return clp->cl_lockowner_id ++; | 75 | return clp->cl_lockowner_id ++; |
210 | } | 76 | } |
211 | 77 | ||
212 | static struct nfs4_state_owner * | 78 | static struct nfs4_state_owner * |
213 | nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) | 79 | nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred) |
214 | { | 80 | { |
215 | struct nfs4_state_owner *sp = NULL; | 81 | struct nfs4_state_owner *sp = NULL; |
216 | 82 | ||
@@ -224,7 +90,7 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) | |||
224 | return sp; | 90 | return sp; |
225 | } | 91 | } |
226 | 92 | ||
227 | struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) | 93 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) |
228 | { | 94 | { |
229 | struct nfs4_state_owner *sp; | 95 | struct nfs4_state_owner *sp; |
230 | struct rpc_cred *cred = NULL; | 96 | struct rpc_cred *cred = NULL; |
@@ -238,7 +104,7 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) | |||
238 | return cred; | 104 | return cred; |
239 | } | 105 | } |
240 | 106 | ||
241 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) | 107 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) |
242 | { | 108 | { |
243 | struct nfs4_state_owner *sp; | 109 | struct nfs4_state_owner *sp; |
244 | 110 | ||
@@ -251,7 +117,7 @@ struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) | |||
251 | } | 117 | } |
252 | 118 | ||
253 | static struct nfs4_state_owner * | 119 | static struct nfs4_state_owner * |
254 | nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred) | 120 | nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) |
255 | { | 121 | { |
256 | struct nfs4_state_owner *sp, *res = NULL; | 122 | struct nfs4_state_owner *sp, *res = NULL; |
257 | 123 | ||
@@ -294,7 +160,7 @@ nfs4_alloc_state_owner(void) | |||
294 | void | 160 | void |
295 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) | 161 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) |
296 | { | 162 | { |
297 | struct nfs4_client *clp = sp->so_client; | 163 | struct nfs_client *clp = sp->so_client; |
298 | spin_lock(&clp->cl_lock); | 164 | spin_lock(&clp->cl_lock); |
299 | list_del_init(&sp->so_list); | 165 | list_del_init(&sp->so_list); |
300 | spin_unlock(&clp->cl_lock); | 166 | spin_unlock(&clp->cl_lock); |
@@ -306,7 +172,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp) | |||
306 | */ | 172 | */ |
307 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) | 173 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) |
308 | { | 174 | { |
309 | struct nfs4_client *clp = server->nfs4_state; | 175 | struct nfs_client *clp = server->nfs_client; |
310 | struct nfs4_state_owner *sp, *new; | 176 | struct nfs4_state_owner *sp, *new; |
311 | 177 | ||
312 | get_rpccred(cred); | 178 | get_rpccred(cred); |
@@ -337,7 +203,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
337 | */ | 203 | */ |
338 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 204 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
339 | { | 205 | { |
340 | struct nfs4_client *clp = sp->so_client; | 206 | struct nfs_client *clp = sp->so_client; |
341 | struct rpc_cred *cred = sp->so_cred; | 207 | struct rpc_cred *cred = sp->so_cred; |
342 | 208 | ||
343 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | 209 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) |
@@ -540,7 +406,7 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
540 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | 406 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) |
541 | { | 407 | { |
542 | struct nfs4_lock_state *lsp; | 408 | struct nfs4_lock_state *lsp; |
543 | struct nfs4_client *clp = state->owner->so_client; | 409 | struct nfs_client *clp = state->owner->so_client; |
544 | 410 | ||
545 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); | 411 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); |
546 | if (lsp == NULL) | 412 | if (lsp == NULL) |
@@ -752,7 +618,7 @@ out: | |||
752 | 618 | ||
753 | static int reclaimer(void *); | 619 | static int reclaimer(void *); |
754 | 620 | ||
755 | static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) | 621 | static inline void nfs4_clear_recover_bit(struct nfs_client *clp) |
756 | { | 622 | { |
757 | smp_mb__before_clear_bit(); | 623 | smp_mb__before_clear_bit(); |
758 | clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); | 624 | clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); |
@@ -764,25 +630,25 @@ static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) | |||
764 | /* | 630 | /* |
765 | * State recovery routine | 631 | * State recovery routine |
766 | */ | 632 | */ |
767 | static void nfs4_recover_state(struct nfs4_client *clp) | 633 | static void nfs4_recover_state(struct nfs_client *clp) |
768 | { | 634 | { |
769 | struct task_struct *task; | 635 | struct task_struct *task; |
770 | 636 | ||
771 | __module_get(THIS_MODULE); | 637 | __module_get(THIS_MODULE); |
772 | atomic_inc(&clp->cl_count); | 638 | atomic_inc(&clp->cl_count); |
773 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", | 639 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", |
774 | NIPQUAD(clp->cl_addr)); | 640 | NIPQUAD(clp->cl_addr.sin_addr)); |
775 | if (!IS_ERR(task)) | 641 | if (!IS_ERR(task)) |
776 | return; | 642 | return; |
777 | nfs4_clear_recover_bit(clp); | 643 | nfs4_clear_recover_bit(clp); |
778 | nfs4_put_client(clp); | 644 | nfs_put_client(clp); |
779 | module_put(THIS_MODULE); | 645 | module_put(THIS_MODULE); |
780 | } | 646 | } |
781 | 647 | ||
782 | /* | 648 | /* |
783 | * Schedule a state recovery attempt | 649 | * Schedule a state recovery attempt |
784 | */ | 650 | */ |
785 | void nfs4_schedule_state_recovery(struct nfs4_client *clp) | 651 | void nfs4_schedule_state_recovery(struct nfs_client *clp) |
786 | { | 652 | { |
787 | if (!clp) | 653 | if (!clp) |
788 | return; | 654 | return; |
@@ -879,7 +745,7 @@ out_err: | |||
879 | return status; | 745 | return status; |
880 | } | 746 | } |
881 | 747 | ||
882 | static void nfs4_state_mark_reclaim(struct nfs4_client *clp) | 748 | static void nfs4_state_mark_reclaim(struct nfs_client *clp) |
883 | { | 749 | { |
884 | struct nfs4_state_owner *sp; | 750 | struct nfs4_state_owner *sp; |
885 | struct nfs4_state *state; | 751 | struct nfs4_state *state; |
@@ -903,7 +769,7 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp) | |||
903 | 769 | ||
904 | static int reclaimer(void *ptr) | 770 | static int reclaimer(void *ptr) |
905 | { | 771 | { |
906 | struct nfs4_client *clp = ptr; | 772 | struct nfs_client *clp = ptr; |
907 | struct nfs4_state_owner *sp; | 773 | struct nfs4_state_owner *sp; |
908 | struct nfs4_state_recovery_ops *ops; | 774 | struct nfs4_state_recovery_ops *ops; |
909 | struct rpc_cred *cred; | 775 | struct rpc_cred *cred; |
@@ -970,12 +836,12 @@ out: | |||
970 | if (status == -NFS4ERR_CB_PATH_DOWN) | 836 | if (status == -NFS4ERR_CB_PATH_DOWN) |
971 | nfs_handle_cb_pathdown(clp); | 837 | nfs_handle_cb_pathdown(clp); |
972 | nfs4_clear_recover_bit(clp); | 838 | nfs4_clear_recover_bit(clp); |
973 | nfs4_put_client(clp); | 839 | nfs_put_client(clp); |
974 | module_put_and_exit(0); | 840 | module_put_and_exit(0); |
975 | return 0; | 841 | return 0; |
976 | out_error: | 842 | out_error: |
977 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", | 843 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", |
978 | NIPQUAD(clp->cl_addr.s_addr), -status); | 844 | NIPQUAD(clp->cl_addr.sin_addr), -status); |
979 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 845 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
980 | goto out; | 846 | goto out; |
981 | } | 847 | } |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 730ec8fb31c6..3dd413f52da1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -58,7 +58,7 @@ | |||
58 | /* Mapping from NFS error code to "errno" error code. */ | 58 | /* Mapping from NFS error code to "errno" error code. */ |
59 | #define errno_NFSERR_IO EIO | 59 | #define errno_NFSERR_IO EIO |
60 | 60 | ||
61 | static int nfs_stat_to_errno(int); | 61 | static int nfs4_stat_to_errno(int); |
62 | 62 | ||
63 | /* NFSv4 COMPOUND tags are only wanted for debugging purposes */ | 63 | /* NFSv4 COMPOUND tags are only wanted for debugging purposes */ |
64 | #ifdef DEBUG | 64 | #ifdef DEBUG |
@@ -128,7 +128,7 @@ static int nfs_stat_to_errno(int); | |||
128 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) | 128 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) |
129 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ | 129 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ |
130 | 1 + nfs4_name_maxsz + \ | 130 | 1 + nfs4_name_maxsz + \ |
131 | nfs4_path_maxsz + \ | 131 | 1 + \ |
132 | nfs4_fattr_maxsz) | 132 | nfs4_fattr_maxsz) |
133 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) | 133 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) |
134 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ | 134 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ |
@@ -529,7 +529,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
529 | if (iap->ia_valid & ATTR_MODE) | 529 | if (iap->ia_valid & ATTR_MODE) |
530 | len += 4; | 530 | len += 4; |
531 | if (iap->ia_valid & ATTR_UID) { | 531 | if (iap->ia_valid & ATTR_UID) { |
532 | owner_namelen = nfs_map_uid_to_name(server->nfs4_state, iap->ia_uid, owner_name); | 532 | owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name); |
533 | if (owner_namelen < 0) { | 533 | if (owner_namelen < 0) { |
534 | printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", | 534 | printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", |
535 | iap->ia_uid); | 535 | iap->ia_uid); |
@@ -541,7 +541,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
541 | len += 4 + (XDR_QUADLEN(owner_namelen) << 2); | 541 | len += 4 + (XDR_QUADLEN(owner_namelen) << 2); |
542 | } | 542 | } |
543 | if (iap->ia_valid & ATTR_GID) { | 543 | if (iap->ia_valid & ATTR_GID) { |
544 | owner_grouplen = nfs_map_gid_to_group(server->nfs4_state, iap->ia_gid, owner_group); | 544 | owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group); |
545 | if (owner_grouplen < 0) { | 545 | if (owner_grouplen < 0) { |
546 | printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", | 546 | printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", |
547 | iap->ia_gid); | 547 | iap->ia_gid); |
@@ -673,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c | |||
673 | 673 | ||
674 | switch (create->ftype) { | 674 | switch (create->ftype) { |
675 | case NF4LNK: | 675 | case NF4LNK: |
676 | RESERVE_SPACE(4 + create->u.symlink->len); | 676 | RESERVE_SPACE(4); |
677 | WRITE32(create->u.symlink->len); | 677 | WRITE32(create->u.symlink.len); |
678 | WRITEMEM(create->u.symlink->name, create->u.symlink->len); | 678 | xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len); |
679 | break; | 679 | break; |
680 | 680 | ||
681 | case NF4BLK: case NF4CHR: | 681 | case NF4BLK: case NF4CHR: |
@@ -1160,7 +1160,7 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con | |||
1160 | return 0; | 1160 | return 0; |
1161 | } | 1161 | } |
1162 | 1162 | ||
1163 | static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid) | 1163 | static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid) |
1164 | { | 1164 | { |
1165 | uint32_t *p; | 1165 | uint32_t *p; |
1166 | 1166 | ||
@@ -1246,7 +1246,7 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien | |||
1246 | return 0; | 1246 | return 0; |
1247 | } | 1247 | } |
1248 | 1248 | ||
1249 | static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state) | 1249 | static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state) |
1250 | { | 1250 | { |
1251 | uint32_t *p; | 1251 | uint32_t *p; |
1252 | 1252 | ||
@@ -1945,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const str | |||
1945 | /* | 1945 | /* |
1946 | * a RENEW request | 1946 | * a RENEW request |
1947 | */ | 1947 | */ |
1948 | static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) | 1948 | static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp) |
1949 | { | 1949 | { |
1950 | struct xdr_stream xdr; | 1950 | struct xdr_stream xdr; |
1951 | struct compound_hdr hdr = { | 1951 | struct compound_hdr hdr = { |
@@ -1975,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nf | |||
1975 | /* | 1975 | /* |
1976 | * a SETCLIENTID_CONFIRM request | 1976 | * a SETCLIENTID_CONFIRM request |
1977 | */ | 1977 | */ |
1978 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) | 1978 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp) |
1979 | { | 1979 | { |
1980 | struct xdr_stream xdr; | 1980 | struct xdr_stream xdr; |
1981 | struct compound_hdr hdr = { | 1981 | struct compound_hdr hdr = { |
@@ -2127,12 +2127,12 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |||
2127 | } | 2127 | } |
2128 | READ32(nfserr); | 2128 | READ32(nfserr); |
2129 | if (nfserr != NFS_OK) | 2129 | if (nfserr != NFS_OK) |
2130 | return -nfs_stat_to_errno(nfserr); | 2130 | return -nfs4_stat_to_errno(nfserr); |
2131 | return 0; | 2131 | return 0; |
2132 | } | 2132 | } |
2133 | 2133 | ||
2134 | /* Dummy routine */ | 2134 | /* Dummy routine */ |
2135 | static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp) | 2135 | static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp) |
2136 | { | 2136 | { |
2137 | uint32_t *p; | 2137 | uint32_t *p; |
2138 | unsigned int strlen; | 2138 | unsigned int strlen; |
@@ -2636,7 +2636,7 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t | |||
2636 | return 0; | 2636 | return 0; |
2637 | } | 2637 | } |
2638 | 2638 | ||
2639 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid) | 2639 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *uid) |
2640 | { | 2640 | { |
2641 | uint32_t len, *p; | 2641 | uint32_t len, *p; |
2642 | 2642 | ||
@@ -2660,7 +2660,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
2660 | return 0; | 2660 | return 0; |
2661 | } | 2661 | } |
2662 | 2662 | ||
2663 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid) | 2663 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *gid) |
2664 | { | 2664 | { |
2665 | uint32_t len, *p; | 2665 | uint32_t len, *p; |
2666 | 2666 | ||
@@ -3051,9 +3051,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons | |||
3051 | fattr->mode |= fmode; | 3051 | fattr->mode |= fmode; |
3052 | if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0) | 3052 | if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0) |
3053 | goto xdr_error; | 3053 | goto xdr_error; |
3054 | if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0) | 3054 | if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0) |
3055 | goto xdr_error; | 3055 | goto xdr_error; |
3056 | if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0) | 3056 | if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0) |
3057 | goto xdr_error; | 3057 | goto xdr_error; |
3058 | if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0) | 3058 | if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0) |
3059 | goto xdr_error; | 3059 | goto xdr_error; |
@@ -3254,7 +3254,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) | |||
3254 | if (decode_space_limit(xdr, &res->maxsize) < 0) | 3254 | if (decode_space_limit(xdr, &res->maxsize) < 0) |
3255 | return -EIO; | 3255 | return -EIO; |
3256 | } | 3256 | } |
3257 | return decode_ace(xdr, NULL, res->server->nfs4_state); | 3257 | return decode_ace(xdr, NULL, res->server->nfs_client); |
3258 | } | 3258 | } |
3259 | 3259 | ||
3260 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | 3260 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) |
@@ -3565,7 +3565,7 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) | |||
3565 | return 0; | 3565 | return 0; |
3566 | } | 3566 | } |
3567 | 3567 | ||
3568 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) | 3568 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) |
3569 | { | 3569 | { |
3570 | uint32_t *p; | 3570 | uint32_t *p; |
3571 | uint32_t opnum; | 3571 | uint32_t opnum; |
@@ -3598,7 +3598,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) | |||
3598 | READ_BUF(len); | 3598 | READ_BUF(len); |
3599 | return -NFSERR_CLID_INUSE; | 3599 | return -NFSERR_CLID_INUSE; |
3600 | } else | 3600 | } else |
3601 | return -nfs_stat_to_errno(nfserr); | 3601 | return -nfs4_stat_to_errno(nfserr); |
3602 | 3602 | ||
3603 | return 0; | 3603 | return 0; |
3604 | } | 3604 | } |
@@ -4256,7 +4256,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsi | |||
4256 | if (!status) | 4256 | if (!status) |
4257 | status = decode_fsinfo(&xdr, fsinfo); | 4257 | status = decode_fsinfo(&xdr, fsinfo); |
4258 | if (!status) | 4258 | if (!status) |
4259 | status = -nfs_stat_to_errno(hdr.status); | 4259 | status = -nfs4_stat_to_errno(hdr.status); |
4260 | return status; | 4260 | return status; |
4261 | } | 4261 | } |
4262 | 4262 | ||
@@ -4335,7 +4335,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) | |||
4335 | * a SETCLIENTID request | 4335 | * a SETCLIENTID request |
4336 | */ | 4336 | */ |
4337 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, | 4337 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, |
4338 | struct nfs4_client *clp) | 4338 | struct nfs_client *clp) |
4339 | { | 4339 | { |
4340 | struct xdr_stream xdr; | 4340 | struct xdr_stream xdr; |
4341 | struct compound_hdr hdr; | 4341 | struct compound_hdr hdr; |
@@ -4346,7 +4346,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, | |||
4346 | if (!status) | 4346 | if (!status) |
4347 | status = decode_setclientid(&xdr, clp); | 4347 | status = decode_setclientid(&xdr, clp); |
4348 | if (!status) | 4348 | if (!status) |
4349 | status = -nfs_stat_to_errno(hdr.status); | 4349 | status = -nfs4_stat_to_errno(hdr.status); |
4350 | return status; | 4350 | return status; |
4351 | } | 4351 | } |
4352 | 4352 | ||
@@ -4368,7 +4368,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s | |||
4368 | if (!status) | 4368 | if (!status) |
4369 | status = decode_fsinfo(&xdr, fsinfo); | 4369 | status = decode_fsinfo(&xdr, fsinfo); |
4370 | if (!status) | 4370 | if (!status) |
4371 | status = -nfs_stat_to_errno(hdr.status); | 4371 | status = -nfs4_stat_to_errno(hdr.status); |
4372 | return status; | 4372 | return status; |
4373 | } | 4373 | } |
4374 | 4374 | ||
@@ -4521,7 +4521,7 @@ static struct { | |||
4521 | * This one is used jointly by NFSv2 and NFSv3. | 4521 | * This one is used jointly by NFSv2 and NFSv3. |
4522 | */ | 4522 | */ |
4523 | static int | 4523 | static int |
4524 | nfs_stat_to_errno(int stat) | 4524 | nfs4_stat_to_errno(int stat) |
4525 | { | 4525 | { |
4526 | int i; | 4526 | int i; |
4527 | for (i = 0; nfs_errtbl[i].stat != -1; i++) { | 4527 | for (i = 0; nfs_errtbl[i].stat != -1; i++) { |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index b3899ea3229e..630e50647bbb 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -66,14 +66,14 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
66 | 66 | ||
67 | dprintk("%s: call getattr\n", __FUNCTION__); | 67 | dprintk("%s: call getattr\n", __FUNCTION__); |
68 | nfs_fattr_init(fattr); | 68 | nfs_fattr_init(fattr); |
69 | status = rpc_call_sync(server->client_sys, &msg, 0); | 69 | status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); |
70 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); | 70 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); |
71 | if (status) | 71 | if (status) |
72 | return status; | 72 | return status; |
73 | dprintk("%s: call statfs\n", __FUNCTION__); | 73 | dprintk("%s: call statfs\n", __FUNCTION__); |
74 | msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS]; | 74 | msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS]; |
75 | msg.rpc_resp = &fsinfo; | 75 | msg.rpc_resp = &fsinfo; |
76 | status = rpc_call_sync(server->client_sys, &msg, 0); | 76 | status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); |
77 | dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); | 77 | dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); |
78 | if (status) | 78 | if (status) |
79 | return status; | 79 | return status; |
@@ -425,16 +425,17 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | |||
425 | } | 425 | } |
426 | 426 | ||
427 | static int | 427 | static int |
428 | nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | 428 | nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, |
429 | struct iattr *sattr, struct nfs_fh *fhandle, | 429 | unsigned int len, struct iattr *sattr) |
430 | struct nfs_fattr *fattr) | ||
431 | { | 430 | { |
431 | struct nfs_fh fhandle; | ||
432 | struct nfs_fattr fattr; | ||
432 | struct nfs_symlinkargs arg = { | 433 | struct nfs_symlinkargs arg = { |
433 | .fromfh = NFS_FH(dir), | 434 | .fromfh = NFS_FH(dir), |
434 | .fromname = name->name, | 435 | .fromname = dentry->d_name.name, |
435 | .fromlen = name->len, | 436 | .fromlen = dentry->d_name.len, |
436 | .topath = path->name, | 437 | .pages = &page, |
437 | .tolen = path->len, | 438 | .pathlen = len, |
438 | .sattr = sattr | 439 | .sattr = sattr |
439 | }; | 440 | }; |
440 | struct rpc_message msg = { | 441 | struct rpc_message msg = { |
@@ -443,13 +444,25 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
443 | }; | 444 | }; |
444 | int status; | 445 | int status; |
445 | 446 | ||
446 | if (path->len > NFS2_MAXPATHLEN) | 447 | if (len > NFS2_MAXPATHLEN) |
447 | return -ENAMETOOLONG; | 448 | return -ENAMETOOLONG; |
448 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); | 449 | |
449 | nfs_fattr_init(fattr); | 450 | dprintk("NFS call symlink %s\n", dentry->d_name.name); |
450 | fhandle->size = 0; | 451 | |
451 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 452 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
452 | nfs_mark_for_revalidate(dir); | 453 | nfs_mark_for_revalidate(dir); |
454 | |||
455 | /* | ||
456 | * V2 SYMLINK requests don't return any attributes. Setting the | ||
457 | * filehandle size to zero indicates to nfs_instantiate that it | ||
458 | * should fill in the data with a LOOKUP call on the wire. | ||
459 | */ | ||
460 | if (status == 0) { | ||
461 | nfs_fattr_init(&fattr); | ||
462 | fhandle.size = 0; | ||
463 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
464 | } | ||
465 | |||
453 | dprintk("NFS reply symlink: %d\n", status); | 466 | dprintk("NFS reply symlink: %d\n", status); |
454 | return status; | 467 | return status; |
455 | } | 468 | } |
@@ -671,7 +684,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
671 | } | 684 | } |
672 | 685 | ||
673 | 686 | ||
674 | struct nfs_rpc_ops nfs_v2_clientops = { | 687 | const struct nfs_rpc_ops nfs_v2_clientops = { |
675 | .version = 2, /* protocol version */ | 688 | .version = 2, /* protocol version */ |
676 | .dentry_ops = &nfs_dentry_operations, | 689 | .dentry_ops = &nfs_dentry_operations, |
677 | .dir_inode_ops = &nfs_dir_inode_operations, | 690 | .dir_inode_ops = &nfs_dir_inode_operations, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index f0aff824a291..69f1549da2b9 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -171,7 +171,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
171 | rdata->args.offset = page_offset(page) + rdata->args.pgbase; | 171 | rdata->args.offset = page_offset(page) + rdata->args.pgbase; |
172 | 172 | ||
173 | dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n", | 173 | dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n", |
174 | NFS_SERVER(inode)->hostname, | 174 | NFS_SERVER(inode)->nfs_client->cl_hostname, |
175 | inode->i_sb->s_id, | 175 | inode->i_sb->s_id, |
176 | (long long)NFS_FILEID(inode), | 176 | (long long)NFS_FILEID(inode), |
177 | (unsigned long long)rdata->args.pgbase, | 177 | (unsigned long long)rdata->args.pgbase, |
@@ -568,8 +568,13 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | |||
568 | 568 | ||
569 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count); | 569 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count); |
570 | 570 | ||
571 | /* Is this a short read? */ | 571 | if (task->tk_status < 0) { |
572 | if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) { | 572 | if (task->tk_status == -ESTALE) { |
573 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | ||
574 | nfs_mark_for_revalidate(data->inode); | ||
575 | } | ||
576 | } else if (resp->count < argp->count && !resp->eof) { | ||
577 | /* This is a short read! */ | ||
573 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 578 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
574 | /* Has the server at least made some progress? */ | 579 | /* Has the server at least made some progress? */ |
575 | if (resp->count != 0) { | 580 | if (resp->count != 0) { |
@@ -616,6 +621,10 @@ int nfs_readpage(struct file *file, struct page *page) | |||
616 | if (error) | 621 | if (error) |
617 | goto out_error; | 622 | goto out_error; |
618 | 623 | ||
624 | error = -ESTALE; | ||
625 | if (NFS_STALE(inode)) | ||
626 | goto out_error; | ||
627 | |||
619 | if (file == NULL) { | 628 | if (file == NULL) { |
620 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 629 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
621 | if (ctx == NULL) | 630 | if (ctx == NULL) |
@@ -678,7 +687,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
678 | }; | 687 | }; |
679 | struct inode *inode = mapping->host; | 688 | struct inode *inode = mapping->host; |
680 | struct nfs_server *server = NFS_SERVER(inode); | 689 | struct nfs_server *server = NFS_SERVER(inode); |
681 | int ret; | 690 | int ret = -ESTALE; |
682 | 691 | ||
683 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", | 692 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", |
684 | inode->i_sb->s_id, | 693 | inode->i_sb->s_id, |
@@ -686,6 +695,9 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
686 | nr_pages); | 695 | nr_pages); |
687 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); | 696 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); |
688 | 697 | ||
698 | if (NFS_STALE(inode)) | ||
699 | goto out; | ||
700 | |||
689 | if (filp == NULL) { | 701 | if (filp == NULL) { |
690 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 702 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
691 | if (desc.ctx == NULL) | 703 | if (desc.ctx == NULL) |
@@ -701,6 +713,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
701 | ret = err; | 713 | ret = err; |
702 | } | 714 | } |
703 | put_nfs_open_context(desc.ctx); | 715 | put_nfs_open_context(desc.ctx); |
716 | out: | ||
704 | return ret; | 717 | return ret; |
705 | } | 718 | } |
706 | 719 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e8a9bee74d9d..b99113b0f65f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -13,6 +13,11 @@ | |||
13 | * | 13 | * |
14 | * Split from inode.c by David Howells <dhowells@redhat.com> | 14 | * Split from inode.c by David Howells <dhowells@redhat.com> |
15 | * | 15 | * |
16 | * - superblocks are indexed on server only - all inodes, dentries, etc. associated with a | ||
17 | * particular server are held in the same superblock | ||
18 | * - NFS superblocks can have several effective roots to the dentry tree | ||
19 | * - directory type roots are spliced into the tree when a path from one root reaches the root | ||
20 | * of another (see nfs_lookup()) | ||
16 | */ | 21 | */ |
17 | 22 | ||
18 | #include <linux/config.h> | 23 | #include <linux/config.h> |
@@ -52,66 +57,12 @@ | |||
52 | 57 | ||
53 | #define NFSDBG_FACILITY NFSDBG_VFS | 58 | #define NFSDBG_FACILITY NFSDBG_VFS |
54 | 59 | ||
55 | /* Maximum number of readahead requests | ||
56 | * FIXME: this should really be a sysctl so that users may tune it to suit | ||
57 | * their needs. People that do NFS over a slow network, might for | ||
58 | * instance want to reduce it to something closer to 1 for improved | ||
59 | * interactive response. | ||
60 | */ | ||
61 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | ||
62 | |||
63 | /* | ||
64 | * RPC cruft for NFS | ||
65 | */ | ||
66 | static struct rpc_version * nfs_version[] = { | ||
67 | NULL, | ||
68 | NULL, | ||
69 | &nfs_version2, | ||
70 | #if defined(CONFIG_NFS_V3) | ||
71 | &nfs_version3, | ||
72 | #elif defined(CONFIG_NFS_V4) | ||
73 | NULL, | ||
74 | #endif | ||
75 | #if defined(CONFIG_NFS_V4) | ||
76 | &nfs_version4, | ||
77 | #endif | ||
78 | }; | ||
79 | |||
80 | static struct rpc_program nfs_program = { | ||
81 | .name = "nfs", | ||
82 | .number = NFS_PROGRAM, | ||
83 | .nrvers = ARRAY_SIZE(nfs_version), | ||
84 | .version = nfs_version, | ||
85 | .stats = &nfs_rpcstat, | ||
86 | .pipe_dir_name = "/nfs", | ||
87 | }; | ||
88 | |||
89 | struct rpc_stat nfs_rpcstat = { | ||
90 | .program = &nfs_program | ||
91 | }; | ||
92 | |||
93 | |||
94 | #ifdef CONFIG_NFS_V3_ACL | ||
95 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | ||
96 | static struct rpc_version * nfsacl_version[] = { | ||
97 | [3] = &nfsacl_version3, | ||
98 | }; | ||
99 | |||
100 | struct rpc_program nfsacl_program = { | ||
101 | .name = "nfsacl", | ||
102 | .number = NFS_ACL_PROGRAM, | ||
103 | .nrvers = ARRAY_SIZE(nfsacl_version), | ||
104 | .version = nfsacl_version, | ||
105 | .stats = &nfsacl_rpcstat, | ||
106 | }; | ||
107 | #endif /* CONFIG_NFS_V3_ACL */ | ||
108 | |||
109 | static void nfs_umount_begin(struct vfsmount *, int); | 60 | static void nfs_umount_begin(struct vfsmount *, int); |
110 | static int nfs_statfs(struct dentry *, struct kstatfs *); | 61 | static int nfs_statfs(struct dentry *, struct kstatfs *); |
111 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 62 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
112 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); | 63 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); |
113 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); | 64 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); |
114 | static int nfs_clone_nfs_sb(struct file_system_type *fs_type, | 65 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, |
115 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 66 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
116 | static void nfs_kill_super(struct super_block *); | 67 | static void nfs_kill_super(struct super_block *); |
117 | 68 | ||
@@ -123,10 +74,10 @@ static struct file_system_type nfs_fs_type = { | |||
123 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 74 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
124 | }; | 75 | }; |
125 | 76 | ||
126 | struct file_system_type clone_nfs_fs_type = { | 77 | struct file_system_type nfs_xdev_fs_type = { |
127 | .owner = THIS_MODULE, | 78 | .owner = THIS_MODULE, |
128 | .name = "nfs", | 79 | .name = "nfs", |
129 | .get_sb = nfs_clone_nfs_sb, | 80 | .get_sb = nfs_xdev_get_sb, |
130 | .kill_sb = nfs_kill_super, | 81 | .kill_sb = nfs_kill_super, |
131 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 82 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
132 | }; | 83 | }; |
@@ -145,10 +96,10 @@ static struct super_operations nfs_sops = { | |||
145 | #ifdef CONFIG_NFS_V4 | 96 | #ifdef CONFIG_NFS_V4 |
146 | static int nfs4_get_sb(struct file_system_type *fs_type, | 97 | static int nfs4_get_sb(struct file_system_type *fs_type, |
147 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 98 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
148 | static int nfs_clone_nfs4_sb(struct file_system_type *fs_type, | 99 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, |
149 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 100 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
150 | static int nfs_referral_nfs4_sb(struct file_system_type *fs_type, | 101 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, |
151 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 102 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
152 | static void nfs4_kill_super(struct super_block *sb); | 103 | static void nfs4_kill_super(struct super_block *sb); |
153 | 104 | ||
154 | static struct file_system_type nfs4_fs_type = { | 105 | static struct file_system_type nfs4_fs_type = { |
@@ -159,18 +110,18 @@ static struct file_system_type nfs4_fs_type = { | |||
159 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 110 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
160 | }; | 111 | }; |
161 | 112 | ||
162 | struct file_system_type clone_nfs4_fs_type = { | 113 | struct file_system_type nfs4_xdev_fs_type = { |
163 | .owner = THIS_MODULE, | 114 | .owner = THIS_MODULE, |
164 | .name = "nfs4", | 115 | .name = "nfs4", |
165 | .get_sb = nfs_clone_nfs4_sb, | 116 | .get_sb = nfs4_xdev_get_sb, |
166 | .kill_sb = nfs4_kill_super, | 117 | .kill_sb = nfs4_kill_super, |
167 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 118 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
168 | }; | 119 | }; |
169 | 120 | ||
170 | struct file_system_type nfs_referral_nfs4_fs_type = { | 121 | struct file_system_type nfs4_referral_fs_type = { |
171 | .owner = THIS_MODULE, | 122 | .owner = THIS_MODULE, |
172 | .name = "nfs4", | 123 | .name = "nfs4", |
173 | .get_sb = nfs_referral_nfs4_sb, | 124 | .get_sb = nfs4_referral_get_sb, |
174 | .kill_sb = nfs4_kill_super, | 125 | .kill_sb = nfs4_kill_super, |
175 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 126 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
176 | }; | 127 | }; |
@@ -187,39 +138,7 @@ static struct super_operations nfs4_sops = { | |||
187 | }; | 138 | }; |
188 | #endif | 139 | #endif |
189 | 140 | ||
190 | #ifdef CONFIG_NFS_V4 | 141 | static struct shrinker *acl_shrinker; |
191 | static const int nfs_set_port_min = 0; | ||
192 | static const int nfs_set_port_max = 65535; | ||
193 | |||
194 | static int param_set_port(const char *val, struct kernel_param *kp) | ||
195 | { | ||
196 | char *endp; | ||
197 | int num = simple_strtol(val, &endp, 0); | ||
198 | if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) | ||
199 | return -EINVAL; | ||
200 | *((int *)kp->arg) = num; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | module_param_call(callback_tcpport, param_set_port, param_get_int, | ||
205 | &nfs_callback_set_tcpport, 0644); | ||
206 | #endif | ||
207 | |||
208 | #ifdef CONFIG_NFS_V4 | ||
209 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | ||
210 | { | ||
211 | char *endp; | ||
212 | int num = simple_strtol(val, &endp, 0); | ||
213 | int jif = num * HZ; | ||
214 | if (endp == val || *endp || num < 0 || jif < num) | ||
215 | return -EINVAL; | ||
216 | *((int *)kp->arg) = jif; | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | ||
221 | &nfs_idmap_cache_timeout, 0644); | ||
222 | #endif | ||
223 | 142 | ||
224 | /* | 143 | /* |
225 | * Register the NFS filesystems | 144 | * Register the NFS filesystems |
@@ -240,6 +159,7 @@ int __init register_nfs_fs(void) | |||
240 | if (ret < 0) | 159 | if (ret < 0) |
241 | goto error_2; | 160 | goto error_2; |
242 | #endif | 161 | #endif |
162 | acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker); | ||
243 | return 0; | 163 | return 0; |
244 | 164 | ||
245 | #ifdef CONFIG_NFS_V4 | 165 | #ifdef CONFIG_NFS_V4 |
@@ -257,6 +177,8 @@ error_0: | |||
257 | */ | 177 | */ |
258 | void __exit unregister_nfs_fs(void) | 178 | void __exit unregister_nfs_fs(void) |
259 | { | 179 | { |
180 | if (acl_shrinker != NULL) | ||
181 | remove_shrinker(acl_shrinker); | ||
260 | #ifdef CONFIG_NFS_V4 | 182 | #ifdef CONFIG_NFS_V4 |
261 | unregister_filesystem(&nfs4_fs_type); | 183 | unregister_filesystem(&nfs4_fs_type); |
262 | nfs_unregister_sysctl(); | 184 | nfs_unregister_sysctl(); |
@@ -269,11 +191,10 @@ void __exit unregister_nfs_fs(void) | |||
269 | */ | 191 | */ |
270 | static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 192 | static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
271 | { | 193 | { |
272 | struct super_block *sb = dentry->d_sb; | 194 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
273 | struct nfs_server *server = NFS_SB(sb); | ||
274 | unsigned char blockbits; | 195 | unsigned char blockbits; |
275 | unsigned long blockres; | 196 | unsigned long blockres; |
276 | struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode); | 197 | struct nfs_fh *fh = NFS_FH(dentry->d_inode); |
277 | struct nfs_fattr fattr; | 198 | struct nfs_fattr fattr; |
278 | struct nfs_fsstat res = { | 199 | struct nfs_fsstat res = { |
279 | .fattr = &fattr, | 200 | .fattr = &fattr, |
@@ -282,7 +203,7 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
282 | 203 | ||
283 | lock_kernel(); | 204 | lock_kernel(); |
284 | 205 | ||
285 | error = server->rpc_ops->statfs(server, rootfh, &res); | 206 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); |
286 | buf->f_type = NFS_SUPER_MAGIC; | 207 | buf->f_type = NFS_SUPER_MAGIC; |
287 | if (error < 0) | 208 | if (error < 0) |
288 | goto out_err; | 209 | goto out_err; |
@@ -292,7 +213,7 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
292 | * case where f_frsize != f_bsize. Eventually we want to | 213 | * case where f_frsize != f_bsize. Eventually we want to |
293 | * report the value of wtmult in this field. | 214 | * report the value of wtmult in this field. |
294 | */ | 215 | */ |
295 | buf->f_frsize = sb->s_blocksize; | 216 | buf->f_frsize = dentry->d_sb->s_blocksize; |
296 | 217 | ||
297 | /* | 218 | /* |
298 | * On most *nix systems, f_blocks, f_bfree, and f_bavail | 219 | * On most *nix systems, f_blocks, f_bfree, and f_bavail |
@@ -301,8 +222,8 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
301 | * thus historically Linux's sys_statfs reports these | 222 | * thus historically Linux's sys_statfs reports these |
302 | * fields in units of f_bsize. | 223 | * fields in units of f_bsize. |
303 | */ | 224 | */ |
304 | buf->f_bsize = sb->s_blocksize; | 225 | buf->f_bsize = dentry->d_sb->s_blocksize; |
305 | blockbits = sb->s_blocksize_bits; | 226 | blockbits = dentry->d_sb->s_blocksize_bits; |
306 | blockres = (1 << blockbits) - 1; | 227 | blockres = (1 << blockbits) - 1; |
307 | buf->f_blocks = (res.tbytes + blockres) >> blockbits; | 228 | buf->f_blocks = (res.tbytes + blockres) >> blockbits; |
308 | buf->f_bfree = (res.fbytes + blockres) >> blockbits; | 229 | buf->f_bfree = (res.fbytes + blockres) >> blockbits; |
@@ -323,9 +244,12 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
323 | 244 | ||
324 | } | 245 | } |
325 | 246 | ||
247 | /* | ||
248 | * Map the security flavour number to a name | ||
249 | */ | ||
326 | static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | 250 | static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) |
327 | { | 251 | { |
328 | static struct { | 252 | static const struct { |
329 | rpc_authflavor_t flavour; | 253 | rpc_authflavor_t flavour; |
330 | const char *str; | 254 | const char *str; |
331 | } sec_flavours[] = { | 255 | } sec_flavours[] = { |
@@ -356,10 +280,10 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | |||
356 | */ | 280 | */ |
357 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) | 281 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) |
358 | { | 282 | { |
359 | static struct proc_nfs_info { | 283 | static const struct proc_nfs_info { |
360 | int flag; | 284 | int flag; |
361 | char *str; | 285 | const char *str; |
362 | char *nostr; | 286 | const char *nostr; |
363 | } nfs_info[] = { | 287 | } nfs_info[] = { |
364 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 288 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
365 | { NFS_MOUNT_INTR, ",intr", "" }, | 289 | { NFS_MOUNT_INTR, ",intr", "" }, |
@@ -369,11 +293,12 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
369 | { NFS_MOUNT_NOACL, ",noacl", "" }, | 293 | { NFS_MOUNT_NOACL, ",noacl", "" }, |
370 | { 0, NULL, NULL } | 294 | { 0, NULL, NULL } |
371 | }; | 295 | }; |
372 | struct proc_nfs_info *nfs_infop; | 296 | const struct proc_nfs_info *nfs_infop; |
297 | struct nfs_client *clp = nfss->nfs_client; | ||
373 | char buf[12]; | 298 | char buf[12]; |
374 | char *proto; | 299 | const char *proto; |
375 | 300 | ||
376 | seq_printf(m, ",vers=%d", nfss->rpc_ops->version); | 301 | seq_printf(m, ",vers=%d", clp->rpc_ops->version); |
377 | seq_printf(m, ",rsize=%d", nfss->rsize); | 302 | seq_printf(m, ",rsize=%d", nfss->rsize); |
378 | seq_printf(m, ",wsize=%d", nfss->wsize); | 303 | seq_printf(m, ",wsize=%d", nfss->wsize); |
379 | if (nfss->acregmin != 3*HZ || showdefaults) | 304 | if (nfss->acregmin != 3*HZ || showdefaults) |
@@ -402,8 +327,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
402 | proto = buf; | 327 | proto = buf; |
403 | } | 328 | } |
404 | seq_printf(m, ",proto=%s", proto); | 329 | seq_printf(m, ",proto=%s", proto); |
405 | seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ); | 330 | seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ); |
406 | seq_printf(m, ",retrans=%u", nfss->retrans_count); | 331 | seq_printf(m, ",retrans=%u", clp->retrans_count); |
407 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); | 332 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); |
408 | } | 333 | } |
409 | 334 | ||
@@ -417,7 +342,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
417 | nfs_show_mount_options(m, nfss, 0); | 342 | nfs_show_mount_options(m, nfss, 0); |
418 | 343 | ||
419 | seq_puts(m, ",addr="); | 344 | seq_puts(m, ",addr="); |
420 | seq_escape(m, nfss->hostname, " \t\n\\"); | 345 | seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\"); |
421 | 346 | ||
422 | return 0; | 347 | return 0; |
423 | } | 348 | } |
@@ -454,7 +379,7 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
454 | seq_printf(m, ",namelen=%d", nfss->namelen); | 379 | seq_printf(m, ",namelen=%d", nfss->namelen); |
455 | 380 | ||
456 | #ifdef CONFIG_NFS_V4 | 381 | #ifdef CONFIG_NFS_V4 |
457 | if (nfss->rpc_ops->version == 4) { | 382 | if (nfss->nfs_client->cl_nfsversion == 4) { |
458 | seq_printf(m, "\n\tnfsv4:\t"); | 383 | seq_printf(m, "\n\tnfsv4:\t"); |
459 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | 384 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); |
460 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | 385 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); |
@@ -501,782 +426,353 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
501 | 426 | ||
502 | /* | 427 | /* |
503 | * Begin unmount by attempting to remove all automounted mountpoints we added | 428 | * Begin unmount by attempting to remove all automounted mountpoints we added |
504 | * in response to traversals | 429 | * in response to xdev traversals and referrals |
505 | */ | 430 | */ |
506 | static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | 431 | static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) |
507 | { | 432 | { |
508 | struct nfs_server *server; | ||
509 | struct rpc_clnt *rpc; | ||
510 | |||
511 | shrink_submounts(vfsmnt, &nfs_automount_list); | 433 | shrink_submounts(vfsmnt, &nfs_automount_list); |
512 | if (!(flags & MNT_FORCE)) | ||
513 | return; | ||
514 | /* -EIO all pending I/O */ | ||
515 | server = NFS_SB(vfsmnt->mnt_sb); | ||
516 | rpc = server->client; | ||
517 | if (!IS_ERR(rpc)) | ||
518 | rpc_killall_tasks(rpc); | ||
519 | rpc = server->client_acl; | ||
520 | if (!IS_ERR(rpc)) | ||
521 | rpc_killall_tasks(rpc); | ||
522 | } | 434 | } |
523 | 435 | ||
524 | /* | 436 | /* |
525 | * Obtain the root inode of the file system. | 437 | * Validate the NFS2/NFS3 mount data |
438 | * - fills in the mount root filehandle | ||
526 | */ | 439 | */ |
527 | static struct inode * | 440 | static int nfs_validate_mount_data(struct nfs_mount_data *data, |
528 | nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) | 441 | struct nfs_fh *mntfh) |
529 | { | 442 | { |
530 | struct nfs_server *server = NFS_SB(sb); | 443 | if (data == NULL) { |
531 | int error; | 444 | dprintk("%s: missing data argument\n", __FUNCTION__); |
532 | 445 | return -EINVAL; | |
533 | error = server->rpc_ops->getroot(server, rootfh, fsinfo); | ||
534 | if (error < 0) { | ||
535 | dprintk("nfs_get_root: getattr error = %d\n", -error); | ||
536 | return ERR_PTR(error); | ||
537 | } | 446 | } |
538 | 447 | ||
539 | server->fsid = fsinfo->fattr->fsid; | 448 | if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { |
540 | return nfs_fhget(sb, rootfh, fsinfo->fattr); | 449 | dprintk("%s: bad mount version\n", __FUNCTION__); |
541 | } | 450 | return -EINVAL; |
542 | 451 | } | |
543 | /* | ||
544 | * Do NFS version-independent mount processing, and sanity checking | ||
545 | */ | ||
546 | static int | ||
547 | nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) | ||
548 | { | ||
549 | struct nfs_server *server; | ||
550 | struct inode *root_inode; | ||
551 | struct nfs_fattr fattr; | ||
552 | struct nfs_fsinfo fsinfo = { | ||
553 | .fattr = &fattr, | ||
554 | }; | ||
555 | struct nfs_pathconf pathinfo = { | ||
556 | .fattr = &fattr, | ||
557 | }; | ||
558 | int no_root_error = 0; | ||
559 | unsigned long max_rpc_payload; | ||
560 | |||
561 | /* We probably want something more informative here */ | ||
562 | snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); | ||
563 | |||
564 | server = NFS_SB(sb); | ||
565 | 452 | ||
566 | sb->s_magic = NFS_SUPER_MAGIC; | 453 | switch (data->version) { |
454 | case 1: | ||
455 | data->namlen = 0; | ||
456 | case 2: | ||
457 | data->bsize = 0; | ||
458 | case 3: | ||
459 | if (data->flags & NFS_MOUNT_VER3) { | ||
460 | dprintk("%s: mount structure version %d does not support NFSv3\n", | ||
461 | __FUNCTION__, | ||
462 | data->version); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | data->root.size = NFS2_FHSIZE; | ||
466 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
467 | case 4: | ||
468 | if (data->flags & NFS_MOUNT_SECFLAVOUR) { | ||
469 | dprintk("%s: mount structure version %d does not support strong security\n", | ||
470 | __FUNCTION__, | ||
471 | data->version); | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | case 5: | ||
475 | memset(data->context, 0, sizeof(data->context)); | ||
476 | } | ||
567 | 477 | ||
568 | server->io_stats = nfs_alloc_iostats(); | 478 | /* Set the pseudoflavor */ |
569 | if (server->io_stats == NULL) | 479 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) |
570 | return -ENOMEM; | 480 | data->pseudoflavor = RPC_AUTH_UNIX; |
571 | 481 | ||
572 | root_inode = nfs_get_root(sb, &server->fh, &fsinfo); | 482 | #ifndef CONFIG_NFS_V3 |
573 | /* Did getting the root inode fail? */ | 483 | /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ |
574 | if (IS_ERR(root_inode)) { | 484 | if (data->flags & NFS_MOUNT_VER3) { |
575 | no_root_error = PTR_ERR(root_inode); | 485 | dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); |
576 | goto out_no_root; | 486 | return -EPROTONOSUPPORT; |
577 | } | ||
578 | sb->s_root = d_alloc_root(root_inode); | ||
579 | if (!sb->s_root) { | ||
580 | no_root_error = -ENOMEM; | ||
581 | goto out_no_root; | ||
582 | } | 487 | } |
583 | sb->s_root->d_op = server->rpc_ops->dentry_ops; | 488 | #endif /* CONFIG_NFS_V3 */ |
584 | |||
585 | /* mount time stamp, in seconds */ | ||
586 | server->mount_time = jiffies; | ||
587 | |||
588 | /* Get some general file system info */ | ||
589 | if (server->namelen == 0 && | ||
590 | server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) | ||
591 | server->namelen = pathinfo.max_namelen; | ||
592 | /* Work out a lot of parameters */ | ||
593 | if (server->rsize == 0) | ||
594 | server->rsize = nfs_block_size(fsinfo.rtpref, NULL); | ||
595 | if (server->wsize == 0) | ||
596 | server->wsize = nfs_block_size(fsinfo.wtpref, NULL); | ||
597 | |||
598 | if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax) | ||
599 | server->rsize = nfs_block_size(fsinfo.rtmax, NULL); | ||
600 | if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax) | ||
601 | server->wsize = nfs_block_size(fsinfo.wtmax, NULL); | ||
602 | |||
603 | max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); | ||
604 | if (server->rsize > max_rpc_payload) | ||
605 | server->rsize = max_rpc_payload; | ||
606 | if (server->rsize > NFS_MAX_FILE_IO_SIZE) | ||
607 | server->rsize = NFS_MAX_FILE_IO_SIZE; | ||
608 | server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
609 | |||
610 | if (server->wsize > max_rpc_payload) | ||
611 | server->wsize = max_rpc_payload; | ||
612 | if (server->wsize > NFS_MAX_FILE_IO_SIZE) | ||
613 | server->wsize = NFS_MAX_FILE_IO_SIZE; | ||
614 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
615 | 489 | ||
616 | if (sb->s_blocksize == 0) | 490 | /* We now require that the mount process passes the remote address */ |
617 | sb->s_blocksize = nfs_block_bits(server->wsize, | 491 | if (data->addr.sin_addr.s_addr == INADDR_ANY) { |
618 | &sb->s_blocksize_bits); | 492 | dprintk("%s: mount program didn't pass remote address!\n", |
619 | server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL); | 493 | __FUNCTION__); |
620 | 494 | return -EINVAL; | |
621 | server->dtsize = nfs_block_size(fsinfo.dtpref, NULL); | ||
622 | if (server->dtsize > PAGE_CACHE_SIZE) | ||
623 | server->dtsize = PAGE_CACHE_SIZE; | ||
624 | if (server->dtsize > server->rsize) | ||
625 | server->dtsize = server->rsize; | ||
626 | |||
627 | if (server->flags & NFS_MOUNT_NOAC) { | ||
628 | server->acregmin = server->acregmax = 0; | ||
629 | server->acdirmin = server->acdirmax = 0; | ||
630 | sb->s_flags |= MS_SYNCHRONOUS; | ||
631 | } | 495 | } |
632 | server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; | ||
633 | 496 | ||
634 | nfs_super_set_maxbytes(sb, fsinfo.maxfilesize); | 497 | /* Prepare the root filehandle */ |
498 | if (data->flags & NFS_MOUNT_VER3) | ||
499 | mntfh->size = data->root.size; | ||
500 | else | ||
501 | mntfh->size = NFS2_FHSIZE; | ||
502 | |||
503 | if (mntfh->size > sizeof(mntfh->data)) { | ||
504 | dprintk("%s: invalid root filehandle\n", __FUNCTION__); | ||
505 | return -EINVAL; | ||
506 | } | ||
635 | 507 | ||
636 | server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0; | 508 | memcpy(mntfh->data, data->root.data, mntfh->size); |
637 | server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0; | 509 | if (mntfh->size < sizeof(mntfh->data)) |
510 | memset(mntfh->data + mntfh->size, 0, | ||
511 | sizeof(mntfh->data) - mntfh->size); | ||
638 | 512 | ||
639 | /* We're airborne Set socket buffersize */ | ||
640 | rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); | ||
641 | return 0; | 513 | return 0; |
642 | /* Yargs. It didn't work out. */ | ||
643 | out_no_root: | ||
644 | dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error); | ||
645 | if (!IS_ERR(root_inode)) | ||
646 | iput(root_inode); | ||
647 | return no_root_error; | ||
648 | } | 514 | } |
649 | 515 | ||
650 | /* | 516 | /* |
651 | * Initialise the timeout values for a connection | 517 | * Initialise the common bits of the superblock |
652 | */ | 518 | */ |
653 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans) | 519 | static inline void nfs_initialise_sb(struct super_block *sb) |
654 | { | 520 | { |
655 | to->to_initval = timeo * HZ / 10; | 521 | struct nfs_server *server = NFS_SB(sb); |
656 | to->to_retries = retrans; | ||
657 | if (!to->to_retries) | ||
658 | to->to_retries = 2; | ||
659 | |||
660 | switch (proto) { | ||
661 | case IPPROTO_TCP: | ||
662 | if (!to->to_initval) | ||
663 | to->to_initval = 60 * HZ; | ||
664 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) | ||
665 | to->to_initval = NFS_MAX_TCP_TIMEOUT; | ||
666 | to->to_increment = to->to_initval; | ||
667 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); | ||
668 | to->to_exponential = 0; | ||
669 | break; | ||
670 | case IPPROTO_UDP: | ||
671 | default: | ||
672 | if (!to->to_initval) | ||
673 | to->to_initval = 11 * HZ / 10; | ||
674 | if (to->to_initval > NFS_MAX_UDP_TIMEOUT) | ||
675 | to->to_initval = NFS_MAX_UDP_TIMEOUT; | ||
676 | to->to_maxval = NFS_MAX_UDP_TIMEOUT; | ||
677 | to->to_exponential = 1; | ||
678 | break; | ||
679 | } | ||
680 | } | ||
681 | 522 | ||
682 | /* | 523 | sb->s_magic = NFS_SUPER_MAGIC; |
683 | * Create an RPC client handle. | ||
684 | */ | ||
685 | static struct rpc_clnt * | ||
686 | nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | ||
687 | { | ||
688 | struct rpc_timeout timeparms; | ||
689 | struct rpc_xprt *xprt = NULL; | ||
690 | struct rpc_clnt *clnt = NULL; | ||
691 | int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP; | ||
692 | |||
693 | nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans); | ||
694 | |||
695 | server->retrans_timeo = timeparms.to_initval; | ||
696 | server->retrans_count = timeparms.to_retries; | ||
697 | |||
698 | /* create transport and client */ | ||
699 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); | ||
700 | if (IS_ERR(xprt)) { | ||
701 | dprintk("%s: cannot create RPC transport. Error = %ld\n", | ||
702 | __FUNCTION__, PTR_ERR(xprt)); | ||
703 | return (struct rpc_clnt *)xprt; | ||
704 | } | ||
705 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | ||
706 | server->rpc_ops->version, data->pseudoflavor); | ||
707 | if (IS_ERR(clnt)) { | ||
708 | dprintk("%s: cannot create RPC client. Error = %ld\n", | ||
709 | __FUNCTION__, PTR_ERR(xprt)); | ||
710 | goto out_fail; | ||
711 | } | ||
712 | 524 | ||
713 | clnt->cl_intr = 1; | 525 | /* We probably want something more informative here */ |
714 | clnt->cl_softrtry = 1; | 526 | snprintf(sb->s_id, sizeof(sb->s_id), |
527 | "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); | ||
528 | |||
529 | if (sb->s_blocksize == 0) | ||
530 | sb->s_blocksize = nfs_block_bits(server->wsize, | ||
531 | &sb->s_blocksize_bits); | ||
715 | 532 | ||
716 | return clnt; | 533 | if (server->flags & NFS_MOUNT_NOAC) |
534 | sb->s_flags |= MS_SYNCHRONOUS; | ||
717 | 535 | ||
718 | out_fail: | 536 | nfs_super_set_maxbytes(sb, server->maxfilesize); |
719 | return clnt; | ||
720 | } | 537 | } |
721 | 538 | ||
722 | /* | 539 | /* |
723 | * Clone a server record | 540 | * Finish setting up an NFS2/3 superblock |
724 | */ | 541 | */ |
725 | static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data) | 542 | static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data) |
726 | { | 543 | { |
727 | struct nfs_server *server = NFS_SB(sb); | 544 | struct nfs_server *server = NFS_SB(sb); |
728 | struct nfs_server *parent = NFS_SB(data->sb); | ||
729 | struct inode *root_inode; | ||
730 | struct nfs_fsinfo fsinfo; | ||
731 | void *err = ERR_PTR(-ENOMEM); | ||
732 | |||
733 | sb->s_op = data->sb->s_op; | ||
734 | sb->s_blocksize = data->sb->s_blocksize; | ||
735 | sb->s_blocksize_bits = data->sb->s_blocksize_bits; | ||
736 | sb->s_maxbytes = data->sb->s_maxbytes; | ||
737 | |||
738 | server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | ||
739 | server->io_stats = nfs_alloc_iostats(); | ||
740 | if (server->io_stats == NULL) | ||
741 | goto out; | ||
742 | |||
743 | server->client = rpc_clone_client(parent->client); | ||
744 | if (IS_ERR((err = server->client))) | ||
745 | goto out; | ||
746 | |||
747 | if (!IS_ERR(parent->client_sys)) { | ||
748 | server->client_sys = rpc_clone_client(parent->client_sys); | ||
749 | if (IS_ERR((err = server->client_sys))) | ||
750 | goto out; | ||
751 | } | ||
752 | if (!IS_ERR(parent->client_acl)) { | ||
753 | server->client_acl = rpc_clone_client(parent->client_acl); | ||
754 | if (IS_ERR((err = server->client_acl))) | ||
755 | goto out; | ||
756 | } | ||
757 | root_inode = nfs_fhget(sb, data->fh, data->fattr); | ||
758 | if (!root_inode) | ||
759 | goto out; | ||
760 | sb->s_root = d_alloc_root(root_inode); | ||
761 | if (!sb->s_root) | ||
762 | goto out_put_root; | ||
763 | fsinfo.fattr = data->fattr; | ||
764 | if (NFS_PROTO(root_inode)->fsinfo(server, data->fh, &fsinfo) == 0) | ||
765 | nfs_super_set_maxbytes(sb, fsinfo.maxfilesize); | ||
766 | sb->s_root->d_op = server->rpc_ops->dentry_ops; | ||
767 | sb->s_flags |= MS_ACTIVE; | ||
768 | return server; | ||
769 | out_put_root: | ||
770 | iput(root_inode); | ||
771 | out: | ||
772 | return err; | ||
773 | } | ||
774 | 545 | ||
775 | /* | 546 | sb->s_blocksize_bits = 0; |
776 | * Copy an existing superblock and attach revised data | 547 | sb->s_blocksize = 0; |
777 | */ | 548 | if (data->bsize) |
778 | static int nfs_clone_generic_sb(struct nfs_clone_mount *data, | 549 | sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); |
779 | struct super_block *(*fill_sb)(struct nfs_server *, struct nfs_clone_mount *), | ||
780 | struct nfs_server *(*fill_server)(struct super_block *, struct nfs_clone_mount *), | ||
781 | struct vfsmount *mnt) | ||
782 | { | ||
783 | struct nfs_server *server; | ||
784 | struct nfs_server *parent = NFS_SB(data->sb); | ||
785 | struct super_block *sb = ERR_PTR(-EINVAL); | ||
786 | char *hostname; | ||
787 | int error = -ENOMEM; | ||
788 | int len; | ||
789 | |||
790 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | ||
791 | if (server == NULL) | ||
792 | goto out_err; | ||
793 | memcpy(server, parent, sizeof(*server)); | ||
794 | hostname = (data->hostname != NULL) ? data->hostname : parent->hostname; | ||
795 | len = strlen(hostname) + 1; | ||
796 | server->hostname = kmalloc(len, GFP_KERNEL); | ||
797 | if (server->hostname == NULL) | ||
798 | goto free_server; | ||
799 | memcpy(server->hostname, hostname, len); | ||
800 | error = rpciod_up(); | ||
801 | if (error != 0) | ||
802 | goto free_hostname; | ||
803 | |||
804 | sb = fill_sb(server, data); | ||
805 | if (IS_ERR(sb)) { | ||
806 | error = PTR_ERR(sb); | ||
807 | goto kill_rpciod; | ||
808 | } | ||
809 | |||
810 | if (sb->s_root) | ||
811 | goto out_rpciod_down; | ||
812 | 550 | ||
813 | server = fill_server(sb, data); | 551 | if (server->flags & NFS_MOUNT_VER3) { |
814 | if (IS_ERR(server)) { | 552 | /* The VFS shouldn't apply the umask to mode bits. We will do |
815 | error = PTR_ERR(server); | 553 | * so ourselves when necessary. |
816 | goto out_deactivate; | 554 | */ |
555 | sb->s_flags |= MS_POSIXACL; | ||
556 | sb->s_time_gran = 1; | ||
817 | } | 557 | } |
818 | return simple_set_mnt(mnt, sb); | 558 | |
819 | out_deactivate: | 559 | sb->s_op = &nfs_sops; |
820 | up_write(&sb->s_umount); | 560 | nfs_initialise_sb(sb); |
821 | deactivate_super(sb); | ||
822 | return error; | ||
823 | out_rpciod_down: | ||
824 | rpciod_down(); | ||
825 | kfree(server->hostname); | ||
826 | kfree(server); | ||
827 | return simple_set_mnt(mnt, sb); | ||
828 | kill_rpciod: | ||
829 | rpciod_down(); | ||
830 | free_hostname: | ||
831 | kfree(server->hostname); | ||
832 | free_server: | ||
833 | kfree(server); | ||
834 | out_err: | ||
835 | return error; | ||
836 | } | 561 | } |
837 | 562 | ||
838 | /* | 563 | /* |
839 | * Set up an NFS2/3 superblock | 564 | * Finish setting up a cloned NFS2/3 superblock |
840 | * | ||
841 | * The way this works is that the mount process passes a structure | ||
842 | * in the data argument which contains the server's IP address | ||
843 | * and the root file handle obtained from the server's mount | ||
844 | * daemon. We stash these away in the private superblock fields. | ||
845 | */ | 565 | */ |
846 | static int | 566 | static void nfs_clone_super(struct super_block *sb, |
847 | nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) | 567 | const struct super_block *old_sb) |
848 | { | 568 | { |
849 | struct nfs_server *server; | 569 | struct nfs_server *server = NFS_SB(sb); |
850 | rpc_authflavor_t authflavor; | ||
851 | 570 | ||
852 | server = NFS_SB(sb); | 571 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; |
853 | sb->s_blocksize_bits = 0; | 572 | sb->s_blocksize = old_sb->s_blocksize; |
854 | sb->s_blocksize = 0; | 573 | sb->s_maxbytes = old_sb->s_maxbytes; |
855 | if (data->bsize) | ||
856 | sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); | ||
857 | if (data->rsize) | ||
858 | server->rsize = nfs_block_size(data->rsize, NULL); | ||
859 | if (data->wsize) | ||
860 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
861 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | ||
862 | |||
863 | server->acregmin = data->acregmin*HZ; | ||
864 | server->acregmax = data->acregmax*HZ; | ||
865 | server->acdirmin = data->acdirmin*HZ; | ||
866 | server->acdirmax = data->acdirmax*HZ; | ||
867 | |||
868 | /* Start lockd here, before we might error out */ | ||
869 | if (!(server->flags & NFS_MOUNT_NONLM)) | ||
870 | lockd_up(); | ||
871 | |||
872 | server->namelen = data->namlen; | ||
873 | server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL); | ||
874 | if (!server->hostname) | ||
875 | return -ENOMEM; | ||
876 | strcpy(server->hostname, data->hostname); | ||
877 | |||
878 | /* Check NFS protocol revision and initialize RPC op vector | ||
879 | * and file handle pool. */ | ||
880 | #ifdef CONFIG_NFS_V3 | ||
881 | if (server->flags & NFS_MOUNT_VER3) { | ||
882 | server->rpc_ops = &nfs_v3_clientops; | ||
883 | server->caps |= NFS_CAP_READDIRPLUS; | ||
884 | } else { | ||
885 | server->rpc_ops = &nfs_v2_clientops; | ||
886 | } | ||
887 | #else | ||
888 | server->rpc_ops = &nfs_v2_clientops; | ||
889 | #endif | ||
890 | 574 | ||
891 | /* Fill in pseudoflavor for mount version < 5 */ | ||
892 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) | ||
893 | data->pseudoflavor = RPC_AUTH_UNIX; | ||
894 | authflavor = data->pseudoflavor; /* save for sb_init() */ | ||
895 | /* XXX maybe we want to add a server->pseudoflavor field */ | ||
896 | |||
897 | /* Create RPC client handles */ | ||
898 | server->client = nfs_create_client(server, data); | ||
899 | if (IS_ERR(server->client)) | ||
900 | return PTR_ERR(server->client); | ||
901 | /* RFC 2623, sec 2.3.2 */ | ||
902 | if (authflavor != RPC_AUTH_UNIX) { | ||
903 | struct rpc_auth *auth; | ||
904 | |||
905 | server->client_sys = rpc_clone_client(server->client); | ||
906 | if (IS_ERR(server->client_sys)) | ||
907 | return PTR_ERR(server->client_sys); | ||
908 | auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys); | ||
909 | if (IS_ERR(auth)) | ||
910 | return PTR_ERR(auth); | ||
911 | } else { | ||
912 | atomic_inc(&server->client->cl_count); | ||
913 | server->client_sys = server->client; | ||
914 | } | ||
915 | if (server->flags & NFS_MOUNT_VER3) { | 575 | if (server->flags & NFS_MOUNT_VER3) { |
916 | #ifdef CONFIG_NFS_V3_ACL | 576 | /* The VFS shouldn't apply the umask to mode bits. We will do |
917 | if (!(server->flags & NFS_MOUNT_NOACL)) { | 577 | * so ourselves when necessary. |
918 | server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); | ||
919 | /* No errors! Assume that Sun nfsacls are supported */ | ||
920 | if (!IS_ERR(server->client_acl)) | ||
921 | server->caps |= NFS_CAP_ACLS; | ||
922 | } | ||
923 | #else | ||
924 | server->flags &= ~NFS_MOUNT_NOACL; | ||
925 | #endif /* CONFIG_NFS_V3_ACL */ | ||
926 | /* | ||
927 | * The VFS shouldn't apply the umask to mode bits. We will | ||
928 | * do so ourselves when necessary. | ||
929 | */ | 578 | */ |
930 | sb->s_flags |= MS_POSIXACL; | 579 | sb->s_flags |= MS_POSIXACL; |
931 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) | ||
932 | server->namelen = NFS3_MAXNAMLEN; | ||
933 | sb->s_time_gran = 1; | 580 | sb->s_time_gran = 1; |
934 | } else { | ||
935 | if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) | ||
936 | server->namelen = NFS2_MAXNAMLEN; | ||
937 | } | 581 | } |
938 | 582 | ||
939 | sb->s_op = &nfs_sops; | 583 | sb->s_op = old_sb->s_op; |
940 | return nfs_sb_init(sb, authflavor); | 584 | nfs_initialise_sb(sb); |
941 | } | 585 | } |
942 | 586 | ||
943 | static int nfs_set_super(struct super_block *s, void *data) | 587 | static int nfs_set_super(struct super_block *s, void *_server) |
944 | { | 588 | { |
945 | s->s_fs_info = data; | 589 | struct nfs_server *server = _server; |
946 | return set_anon_super(s, data); | 590 | int ret; |
591 | |||
592 | s->s_fs_info = server; | ||
593 | ret = set_anon_super(s, server); | ||
594 | if (ret == 0) | ||
595 | server->s_dev = s->s_dev; | ||
596 | return ret; | ||
947 | } | 597 | } |
948 | 598 | ||
949 | static int nfs_compare_super(struct super_block *sb, void *data) | 599 | static int nfs_compare_super(struct super_block *sb, void *data) |
950 | { | 600 | { |
951 | struct nfs_server *server = data; | 601 | struct nfs_server *server = data, *old = NFS_SB(sb); |
952 | struct nfs_server *old = NFS_SB(sb); | ||
953 | 602 | ||
954 | if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr) | 603 | if (old->nfs_client != server->nfs_client) |
955 | return 0; | 604 | return 0; |
956 | if (old->addr.sin_port != server->addr.sin_port) | 605 | if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) |
957 | return 0; | 606 | return 0; |
958 | return !nfs_compare_fh(&old->fh, &server->fh); | 607 | return 1; |
959 | } | 608 | } |
960 | 609 | ||
961 | static int nfs_get_sb(struct file_system_type *fs_type, | 610 | static int nfs_get_sb(struct file_system_type *fs_type, |
962 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 611 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
963 | { | 612 | { |
964 | int error; | ||
965 | struct nfs_server *server = NULL; | 613 | struct nfs_server *server = NULL; |
966 | struct super_block *s; | 614 | struct super_block *s; |
967 | struct nfs_fh *root; | 615 | struct nfs_fh mntfh; |
968 | struct nfs_mount_data *data = raw_data; | 616 | struct nfs_mount_data *data = raw_data; |
617 | struct dentry *mntroot; | ||
618 | int error; | ||
969 | 619 | ||
970 | error = -EINVAL; | 620 | /* Validate the mount data */ |
971 | if (data == NULL) { | 621 | error = nfs_validate_mount_data(data, &mntfh); |
972 | dprintk("%s: missing data argument\n", __FUNCTION__); | 622 | if (error < 0) |
973 | goto out_err_noserver; | 623 | return error; |
974 | } | ||
975 | if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { | ||
976 | dprintk("%s: bad mount version\n", __FUNCTION__); | ||
977 | goto out_err_noserver; | ||
978 | } | ||
979 | switch (data->version) { | ||
980 | case 1: | ||
981 | data->namlen = 0; | ||
982 | case 2: | ||
983 | data->bsize = 0; | ||
984 | case 3: | ||
985 | if (data->flags & NFS_MOUNT_VER3) { | ||
986 | dprintk("%s: mount structure version %d does not support NFSv3\n", | ||
987 | __FUNCTION__, | ||
988 | data->version); | ||
989 | goto out_err_noserver; | ||
990 | } | ||
991 | data->root.size = NFS2_FHSIZE; | ||
992 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
993 | case 4: | ||
994 | if (data->flags & NFS_MOUNT_SECFLAVOUR) { | ||
995 | dprintk("%s: mount structure version %d does not support strong security\n", | ||
996 | __FUNCTION__, | ||
997 | data->version); | ||
998 | goto out_err_noserver; | ||
999 | } | ||
1000 | case 5: | ||
1001 | memset(data->context, 0, sizeof(data->context)); | ||
1002 | } | ||
1003 | #ifndef CONFIG_NFS_V3 | ||
1004 | /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ | ||
1005 | error = -EPROTONOSUPPORT; | ||
1006 | if (data->flags & NFS_MOUNT_VER3) { | ||
1007 | dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); | ||
1008 | goto out_err_noserver; | ||
1009 | } | ||
1010 | #endif /* CONFIG_NFS_V3 */ | ||
1011 | 624 | ||
1012 | error = -ENOMEM; | 625 | /* Get a volume representation */ |
1013 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); | 626 | server = nfs_create_server(data, &mntfh); |
1014 | if (!server) | 627 | if (IS_ERR(server)) { |
628 | error = PTR_ERR(server); | ||
1015 | goto out_err_noserver; | 629 | goto out_err_noserver; |
1016 | /* Zero out the NFS state stuff */ | ||
1017 | init_nfsv4_state(server); | ||
1018 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | ||
1019 | |||
1020 | root = &server->fh; | ||
1021 | if (data->flags & NFS_MOUNT_VER3) | ||
1022 | root->size = data->root.size; | ||
1023 | else | ||
1024 | root->size = NFS2_FHSIZE; | ||
1025 | error = -EINVAL; | ||
1026 | if (root->size > sizeof(root->data)) { | ||
1027 | dprintk("%s: invalid root filehandle\n", __FUNCTION__); | ||
1028 | goto out_err; | ||
1029 | } | ||
1030 | memcpy(root->data, data->root.data, root->size); | ||
1031 | |||
1032 | /* We now require that the mount process passes the remote address */ | ||
1033 | memcpy(&server->addr, &data->addr, sizeof(server->addr)); | ||
1034 | if (server->addr.sin_addr.s_addr == INADDR_ANY) { | ||
1035 | dprintk("%s: mount program didn't pass remote address!\n", | ||
1036 | __FUNCTION__); | ||
1037 | goto out_err; | ||
1038 | } | ||
1039 | |||
1040 | /* Fire up rpciod if not yet running */ | ||
1041 | error = rpciod_up(); | ||
1042 | if (error < 0) { | ||
1043 | dprintk("%s: couldn't start rpciod! Error = %d\n", | ||
1044 | __FUNCTION__, error); | ||
1045 | goto out_err; | ||
1046 | } | 630 | } |
1047 | 631 | ||
632 | /* Get a superblock - note that we may end up sharing one that already exists */ | ||
1048 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | 633 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); |
1049 | if (IS_ERR(s)) { | 634 | if (IS_ERR(s)) { |
1050 | error = PTR_ERR(s); | 635 | error = PTR_ERR(s); |
1051 | goto out_err_rpciod; | 636 | goto out_err_nosb; |
1052 | } | 637 | } |
1053 | 638 | ||
1054 | if (s->s_root) | 639 | if (s->s_fs_info != server) { |
1055 | goto out_rpciod_down; | 640 | nfs_free_server(server); |
641 | server = NULL; | ||
642 | } | ||
1056 | 643 | ||
1057 | s->s_flags = flags; | 644 | if (!s->s_root) { |
645 | /* initial superblock/root creation */ | ||
646 | s->s_flags = flags; | ||
647 | nfs_fill_super(s, data); | ||
648 | } | ||
1058 | 649 | ||
1059 | error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0); | 650 | mntroot = nfs_get_root(s, &mntfh); |
1060 | if (error) { | 651 | if (IS_ERR(mntroot)) { |
1061 | up_write(&s->s_umount); | 652 | error = PTR_ERR(mntroot); |
1062 | deactivate_super(s); | 653 | goto error_splat_super; |
1063 | return error; | ||
1064 | } | 654 | } |
1065 | s->s_flags |= MS_ACTIVE; | ||
1066 | return simple_set_mnt(mnt, s); | ||
1067 | 655 | ||
1068 | out_rpciod_down: | 656 | s->s_flags |= MS_ACTIVE; |
1069 | rpciod_down(); | 657 | mnt->mnt_sb = s; |
1070 | kfree(server); | 658 | mnt->mnt_root = mntroot; |
1071 | return simple_set_mnt(mnt, s); | 659 | return 0; |
1072 | 660 | ||
1073 | out_err_rpciod: | 661 | out_err_nosb: |
1074 | rpciod_down(); | 662 | nfs_free_server(server); |
1075 | out_err: | ||
1076 | kfree(server); | ||
1077 | out_err_noserver: | 663 | out_err_noserver: |
1078 | return error; | 664 | return error; |
665 | |||
666 | error_splat_super: | ||
667 | up_write(&s->s_umount); | ||
668 | deactivate_super(s); | ||
669 | return error; | ||
1079 | } | 670 | } |
1080 | 671 | ||
672 | /* | ||
673 | * Destroy an NFS2/3 superblock | ||
674 | */ | ||
1081 | static void nfs_kill_super(struct super_block *s) | 675 | static void nfs_kill_super(struct super_block *s) |
1082 | { | 676 | { |
1083 | struct nfs_server *server = NFS_SB(s); | 677 | struct nfs_server *server = NFS_SB(s); |
1084 | 678 | ||
1085 | kill_anon_super(s); | 679 | kill_anon_super(s); |
1086 | 680 | nfs_free_server(server); | |
1087 | if (!IS_ERR(server->client)) | ||
1088 | rpc_shutdown_client(server->client); | ||
1089 | if (!IS_ERR(server->client_sys)) | ||
1090 | rpc_shutdown_client(server->client_sys); | ||
1091 | if (!IS_ERR(server->client_acl)) | ||
1092 | rpc_shutdown_client(server->client_acl); | ||
1093 | |||
1094 | if (!(server->flags & NFS_MOUNT_NONLM)) | ||
1095 | lockd_down(); /* release rpc.lockd */ | ||
1096 | |||
1097 | rpciod_down(); /* release rpciod */ | ||
1098 | |||
1099 | nfs_free_iostats(server->io_stats); | ||
1100 | kfree(server->hostname); | ||
1101 | kfree(server); | ||
1102 | nfs_release_automount_timer(); | ||
1103 | } | ||
1104 | |||
1105 | static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data) | ||
1106 | { | ||
1107 | struct super_block *sb; | ||
1108 | |||
1109 | server->fsid = data->fattr->fsid; | ||
1110 | nfs_copy_fh(&server->fh, data->fh); | ||
1111 | sb = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); | ||
1112 | if (!IS_ERR(sb) && sb->s_root == NULL && !(server->flags & NFS_MOUNT_NONLM)) | ||
1113 | lockd_up(); | ||
1114 | return sb; | ||
1115 | } | 681 | } |
1116 | 682 | ||
1117 | static int nfs_clone_nfs_sb(struct file_system_type *fs_type, | 683 | /* |
1118 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 684 | * Clone an NFS2/3 server record on xdev traversal (FSID-change) |
685 | */ | ||
686 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | ||
687 | const char *dev_name, void *raw_data, | ||
688 | struct vfsmount *mnt) | ||
1119 | { | 689 | { |
1120 | struct nfs_clone_mount *data = raw_data; | 690 | struct nfs_clone_mount *data = raw_data; |
1121 | return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt); | 691 | struct super_block *s; |
1122 | } | 692 | struct nfs_server *server; |
693 | struct dentry *mntroot; | ||
694 | int error; | ||
1123 | 695 | ||
1124 | #ifdef CONFIG_NFS_V4 | 696 | dprintk("--> nfs_xdev_get_sb()\n"); |
1125 | static struct rpc_clnt *nfs4_create_client(struct nfs_server *server, | ||
1126 | struct rpc_timeout *timeparms, int proto, rpc_authflavor_t flavor) | ||
1127 | { | ||
1128 | struct nfs4_client *clp; | ||
1129 | struct rpc_xprt *xprt = NULL; | ||
1130 | struct rpc_clnt *clnt = NULL; | ||
1131 | int err = -EIO; | ||
1132 | |||
1133 | clp = nfs4_get_client(&server->addr.sin_addr); | ||
1134 | if (!clp) { | ||
1135 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); | ||
1136 | return ERR_PTR(err); | ||
1137 | } | ||
1138 | 697 | ||
1139 | /* Now create transport and client */ | 698 | /* create a new volume representation */ |
1140 | down_write(&clp->cl_sem); | 699 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); |
1141 | if (IS_ERR(clp->cl_rpcclient)) { | 700 | if (IS_ERR(server)) { |
1142 | xprt = xprt_create_proto(proto, &server->addr, timeparms); | 701 | error = PTR_ERR(server); |
1143 | if (IS_ERR(xprt)) { | 702 | goto out_err_noserver; |
1144 | up_write(&clp->cl_sem); | ||
1145 | err = PTR_ERR(xprt); | ||
1146 | dprintk("%s: cannot create RPC transport. Error = %d\n", | ||
1147 | __FUNCTION__, err); | ||
1148 | goto out_fail; | ||
1149 | } | ||
1150 | /* Bind to a reserved port! */ | ||
1151 | xprt->resvport = 1; | ||
1152 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | ||
1153 | server->rpc_ops->version, flavor); | ||
1154 | if (IS_ERR(clnt)) { | ||
1155 | up_write(&clp->cl_sem); | ||
1156 | err = PTR_ERR(clnt); | ||
1157 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1158 | __FUNCTION__, err); | ||
1159 | goto out_fail; | ||
1160 | } | ||
1161 | clnt->cl_intr = 1; | ||
1162 | clnt->cl_softrtry = 1; | ||
1163 | clp->cl_rpcclient = clnt; | ||
1164 | memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); | ||
1165 | nfs_idmap_new(clp); | ||
1166 | } | ||
1167 | list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); | ||
1168 | clnt = rpc_clone_client(clp->cl_rpcclient); | ||
1169 | if (!IS_ERR(clnt)) | ||
1170 | server->nfs4_state = clp; | ||
1171 | up_write(&clp->cl_sem); | ||
1172 | clp = NULL; | ||
1173 | |||
1174 | if (IS_ERR(clnt)) { | ||
1175 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1176 | __FUNCTION__, err); | ||
1177 | return clnt; | ||
1178 | } | 703 | } |
1179 | 704 | ||
1180 | if (server->nfs4_state->cl_idmap == NULL) { | 705 | /* Get a superblock - note that we may end up sharing one that already exists */ |
1181 | dprintk("%s: failed to create idmapper.\n", __FUNCTION__); | 706 | s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); |
1182 | return ERR_PTR(-ENOMEM); | 707 | if (IS_ERR(s)) { |
708 | error = PTR_ERR(s); | ||
709 | goto out_err_nosb; | ||
1183 | } | 710 | } |
1184 | 711 | ||
1185 | if (clnt->cl_auth->au_flavor != flavor) { | 712 | if (s->s_fs_info != server) { |
1186 | struct rpc_auth *auth; | 713 | nfs_free_server(server); |
1187 | 714 | server = NULL; | |
1188 | auth = rpcauth_create(flavor, clnt); | ||
1189 | if (IS_ERR(auth)) { | ||
1190 | dprintk("%s: couldn't create credcache!\n", __FUNCTION__); | ||
1191 | return (struct rpc_clnt *)auth; | ||
1192 | } | ||
1193 | } | 715 | } |
1194 | return clnt; | ||
1195 | |||
1196 | out_fail: | ||
1197 | if (clp) | ||
1198 | nfs4_put_client(clp); | ||
1199 | return ERR_PTR(err); | ||
1200 | } | ||
1201 | |||
1202 | /* | ||
1203 | * Set up an NFS4 superblock | ||
1204 | */ | ||
1205 | static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent) | ||
1206 | { | ||
1207 | struct nfs_server *server; | ||
1208 | struct rpc_timeout timeparms; | ||
1209 | rpc_authflavor_t authflavour; | ||
1210 | int err = -EIO; | ||
1211 | 716 | ||
1212 | sb->s_blocksize_bits = 0; | 717 | if (!s->s_root) { |
1213 | sb->s_blocksize = 0; | 718 | /* initial superblock/root creation */ |
1214 | server = NFS_SB(sb); | 719 | s->s_flags = flags; |
1215 | if (data->rsize != 0) | 720 | nfs_clone_super(s, data->sb); |
1216 | server->rsize = nfs_block_size(data->rsize, NULL); | 721 | } |
1217 | if (data->wsize != 0) | ||
1218 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
1219 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | ||
1220 | server->caps = NFS_CAP_ATOMIC_OPEN; | ||
1221 | 722 | ||
1222 | server->acregmin = data->acregmin*HZ; | 723 | mntroot = nfs_get_root(s, data->fh); |
1223 | server->acregmax = data->acregmax*HZ; | 724 | if (IS_ERR(mntroot)) { |
1224 | server->acdirmin = data->acdirmin*HZ; | 725 | error = PTR_ERR(mntroot); |
1225 | server->acdirmax = data->acdirmax*HZ; | 726 | goto error_splat_super; |
727 | } | ||
1226 | 728 | ||
1227 | server->rpc_ops = &nfs_v4_clientops; | 729 | s->s_flags |= MS_ACTIVE; |
730 | mnt->mnt_sb = s; | ||
731 | mnt->mnt_root = mntroot; | ||
1228 | 732 | ||
1229 | nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans); | 733 | dprintk("<-- nfs_xdev_get_sb() = 0\n"); |
734 | return 0; | ||
1230 | 735 | ||
1231 | server->retrans_timeo = timeparms.to_initval; | 736 | out_err_nosb: |
1232 | server->retrans_count = timeparms.to_retries; | 737 | nfs_free_server(server); |
738 | out_err_noserver: | ||
739 | dprintk("<-- nfs_xdev_get_sb() = %d [error]\n", error); | ||
740 | return error; | ||
1233 | 741 | ||
1234 | /* Now create transport and client */ | 742 | error_splat_super: |
1235 | authflavour = RPC_AUTH_UNIX; | 743 | up_write(&s->s_umount); |
1236 | if (data->auth_flavourlen != 0) { | 744 | deactivate_super(s); |
1237 | if (data->auth_flavourlen != 1) { | 745 | dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error); |
1238 | dprintk("%s: Invalid number of RPC auth flavours %d.\n", | 746 | return error; |
1239 | __FUNCTION__, data->auth_flavourlen); | 747 | } |
1240 | err = -EINVAL; | ||
1241 | goto out_fail; | ||
1242 | } | ||
1243 | if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { | ||
1244 | err = -EFAULT; | ||
1245 | goto out_fail; | ||
1246 | } | ||
1247 | } | ||
1248 | 748 | ||
1249 | server->client = nfs4_create_client(server, &timeparms, data->proto, authflavour); | 749 | #ifdef CONFIG_NFS_V4 |
1250 | if (IS_ERR(server->client)) { | ||
1251 | err = PTR_ERR(server->client); | ||
1252 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1253 | __FUNCTION__, err); | ||
1254 | goto out_fail; | ||
1255 | } | ||
1256 | 750 | ||
751 | /* | ||
752 | * Finish setting up a cloned NFS4 superblock | ||
753 | */ | ||
754 | static void nfs4_clone_super(struct super_block *sb, | ||
755 | const struct super_block *old_sb) | ||
756 | { | ||
757 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; | ||
758 | sb->s_blocksize = old_sb->s_blocksize; | ||
759 | sb->s_maxbytes = old_sb->s_maxbytes; | ||
1257 | sb->s_time_gran = 1; | 760 | sb->s_time_gran = 1; |
1258 | 761 | sb->s_op = old_sb->s_op; | |
1259 | sb->s_op = &nfs4_sops; | 762 | nfs_initialise_sb(sb); |
1260 | err = nfs_sb_init(sb, authflavour); | ||
1261 | |||
1262 | out_fail: | ||
1263 | return err; | ||
1264 | } | 763 | } |
1265 | 764 | ||
1266 | static int nfs4_compare_super(struct super_block *sb, void *data) | 765 | /* |
766 | * Set up an NFS4 superblock | ||
767 | */ | ||
768 | static void nfs4_fill_super(struct super_block *sb) | ||
1267 | { | 769 | { |
1268 | struct nfs_server *server = data; | 770 | sb->s_time_gran = 1; |
1269 | struct nfs_server *old = NFS_SB(sb); | 771 | sb->s_op = &nfs4_sops; |
1270 | 772 | nfs_initialise_sb(sb); | |
1271 | if (strcmp(server->hostname, old->hostname) != 0) | ||
1272 | return 0; | ||
1273 | if (strcmp(server->mnt_path, old->mnt_path) != 0) | ||
1274 | return 0; | ||
1275 | return 1; | ||
1276 | } | 773 | } |
1277 | 774 | ||
1278 | static void * | 775 | static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) |
1279 | nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) | ||
1280 | { | 776 | { |
1281 | void *p = NULL; | 777 | void *p = NULL; |
1282 | 778 | ||
@@ -1297,14 +793,22 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) | |||
1297 | return dst; | 793 | return dst; |
1298 | } | 794 | } |
1299 | 795 | ||
796 | /* | ||
797 | * Get the superblock for an NFS4 mountpoint | ||
798 | */ | ||
1300 | static int nfs4_get_sb(struct file_system_type *fs_type, | 799 | static int nfs4_get_sb(struct file_system_type *fs_type, |
1301 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 800 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
1302 | { | 801 | { |
1303 | int error; | ||
1304 | struct nfs_server *server; | ||
1305 | struct super_block *s; | ||
1306 | struct nfs4_mount_data *data = raw_data; | 802 | struct nfs4_mount_data *data = raw_data; |
803 | struct super_block *s; | ||
804 | struct nfs_server *server; | ||
805 | struct sockaddr_in addr; | ||
806 | rpc_authflavor_t authflavour; | ||
807 | struct nfs_fh mntfh; | ||
808 | struct dentry *mntroot; | ||
809 | char *mntpath = NULL, *hostname = NULL, ip_addr[16]; | ||
1307 | void *p; | 810 | void *p; |
811 | int error; | ||
1308 | 812 | ||
1309 | if (data == NULL) { | 813 | if (data == NULL) { |
1310 | dprintk("%s: missing data argument\n", __FUNCTION__); | 814 | dprintk("%s: missing data argument\n", __FUNCTION__); |
@@ -1315,84 +819,112 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
1315 | return -EINVAL; | 819 | return -EINVAL; |
1316 | } | 820 | } |
1317 | 821 | ||
1318 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); | 822 | /* We now require that the mount process passes the remote address */ |
1319 | if (!server) | 823 | if (data->host_addrlen != sizeof(addr)) |
1320 | return -ENOMEM; | 824 | return -EINVAL; |
1321 | /* Zero out the NFS state stuff */ | 825 | |
1322 | init_nfsv4_state(server); | 826 | if (copy_from_user(&addr, data->host_addr, sizeof(addr))) |
1323 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | 827 | return -EFAULT; |
828 | |||
829 | if (addr.sin_family != AF_INET || | ||
830 | addr.sin_addr.s_addr == INADDR_ANY | ||
831 | ) { | ||
832 | dprintk("%s: mount program didn't pass remote IP address!\n", | ||
833 | __FUNCTION__); | ||
834 | return -EINVAL; | ||
835 | } | ||
836 | /* RFC3530: The default port for NFS is 2049 */ | ||
837 | if (addr.sin_port == 0) | ||
838 | addr.sin_port = NFS_PORT; | ||
839 | |||
840 | /* Grab the authentication type */ | ||
841 | authflavour = RPC_AUTH_UNIX; | ||
842 | if (data->auth_flavourlen != 0) { | ||
843 | if (data->auth_flavourlen != 1) { | ||
844 | dprintk("%s: Invalid number of RPC auth flavours %d.\n", | ||
845 | __FUNCTION__, data->auth_flavourlen); | ||
846 | error = -EINVAL; | ||
847 | goto out_err_noserver; | ||
848 | } | ||
849 | |||
850 | if (copy_from_user(&authflavour, data->auth_flavours, | ||
851 | sizeof(authflavour))) { | ||
852 | error = -EFAULT; | ||
853 | goto out_err_noserver; | ||
854 | } | ||
855 | } | ||
1324 | 856 | ||
1325 | p = nfs_copy_user_string(NULL, &data->hostname, 256); | 857 | p = nfs_copy_user_string(NULL, &data->hostname, 256); |
1326 | if (IS_ERR(p)) | 858 | if (IS_ERR(p)) |
1327 | goto out_err; | 859 | goto out_err; |
1328 | server->hostname = p; | 860 | hostname = p; |
1329 | 861 | ||
1330 | p = nfs_copy_user_string(NULL, &data->mnt_path, 1024); | 862 | p = nfs_copy_user_string(NULL, &data->mnt_path, 1024); |
1331 | if (IS_ERR(p)) | 863 | if (IS_ERR(p)) |
1332 | goto out_err; | 864 | goto out_err; |
1333 | server->mnt_path = p; | 865 | mntpath = p; |
866 | |||
867 | dprintk("MNTPATH: %s\n", mntpath); | ||
1334 | 868 | ||
1335 | p = nfs_copy_user_string(server->ip_addr, &data->client_addr, | 869 | p = nfs_copy_user_string(ip_addr, &data->client_addr, |
1336 | sizeof(server->ip_addr) - 1); | 870 | sizeof(ip_addr) - 1); |
1337 | if (IS_ERR(p)) | 871 | if (IS_ERR(p)) |
1338 | goto out_err; | 872 | goto out_err; |
1339 | 873 | ||
1340 | /* We now require that the mount process passes the remote address */ | 874 | /* Get a volume representation */ |
1341 | if (data->host_addrlen != sizeof(server->addr)) { | 875 | server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr, |
1342 | error = -EINVAL; | 876 | authflavour, &mntfh); |
1343 | goto out_free; | 877 | if (IS_ERR(server)) { |
1344 | } | 878 | error = PTR_ERR(server); |
1345 | if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) { | 879 | goto out_err_noserver; |
1346 | error = -EFAULT; | ||
1347 | goto out_free; | ||
1348 | } | ||
1349 | if (server->addr.sin_family != AF_INET || | ||
1350 | server->addr.sin_addr.s_addr == INADDR_ANY) { | ||
1351 | dprintk("%s: mount program didn't pass remote IP address!\n", | ||
1352 | __FUNCTION__); | ||
1353 | error = -EINVAL; | ||
1354 | goto out_free; | ||
1355 | } | ||
1356 | |||
1357 | /* Fire up rpciod if not yet running */ | ||
1358 | error = rpciod_up(); | ||
1359 | if (error < 0) { | ||
1360 | dprintk("%s: couldn't start rpciod! Error = %d\n", | ||
1361 | __FUNCTION__, error); | ||
1362 | goto out_free; | ||
1363 | } | 880 | } |
1364 | 881 | ||
1365 | s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); | 882 | /* Get a superblock - note that we may end up sharing one that already exists */ |
1366 | 883 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | |
1367 | if (IS_ERR(s)) { | 884 | if (IS_ERR(s)) { |
1368 | error = PTR_ERR(s); | 885 | error = PTR_ERR(s); |
1369 | goto out_free; | 886 | goto out_free; |
1370 | } | 887 | } |
1371 | 888 | ||
1372 | if (s->s_root) { | 889 | if (s->s_fs_info != server) { |
1373 | kfree(server->mnt_path); | 890 | nfs_free_server(server); |
1374 | kfree(server->hostname); | 891 | server = NULL; |
1375 | kfree(server); | ||
1376 | return simple_set_mnt(mnt, s); | ||
1377 | } | 892 | } |
1378 | 893 | ||
1379 | s->s_flags = flags; | 894 | if (!s->s_root) { |
895 | /* initial superblock/root creation */ | ||
896 | s->s_flags = flags; | ||
897 | nfs4_fill_super(s); | ||
898 | } | ||
1380 | 899 | ||
1381 | error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0); | 900 | mntroot = nfs4_get_root(s, &mntfh); |
1382 | if (error) { | 901 | if (IS_ERR(mntroot)) { |
1383 | up_write(&s->s_umount); | 902 | error = PTR_ERR(mntroot); |
1384 | deactivate_super(s); | 903 | goto error_splat_super; |
1385 | return error; | ||
1386 | } | 904 | } |
905 | |||
1387 | s->s_flags |= MS_ACTIVE; | 906 | s->s_flags |= MS_ACTIVE; |
1388 | return simple_set_mnt(mnt, s); | 907 | mnt->mnt_sb = s; |
908 | mnt->mnt_root = mntroot; | ||
909 | kfree(mntpath); | ||
910 | kfree(hostname); | ||
911 | return 0; | ||
912 | |||
1389 | out_err: | 913 | out_err: |
1390 | error = PTR_ERR(p); | 914 | error = PTR_ERR(p); |
915 | goto out_err_noserver; | ||
916 | |||
1391 | out_free: | 917 | out_free: |
1392 | kfree(server->mnt_path); | 918 | nfs_free_server(server); |
1393 | kfree(server->hostname); | 919 | out_err_noserver: |
1394 | kfree(server); | 920 | kfree(mntpath); |
921 | kfree(hostname); | ||
1395 | return error; | 922 | return error; |
923 | |||
924 | error_splat_super: | ||
925 | up_write(&s->s_umount); | ||
926 | deactivate_super(s); | ||
927 | goto out_err_noserver; | ||
1396 | } | 928 | } |
1397 | 929 | ||
1398 | static void nfs4_kill_super(struct super_block *sb) | 930 | static void nfs4_kill_super(struct super_block *sb) |
@@ -1403,135 +935,140 @@ static void nfs4_kill_super(struct super_block *sb) | |||
1403 | kill_anon_super(sb); | 935 | kill_anon_super(sb); |
1404 | 936 | ||
1405 | nfs4_renewd_prepare_shutdown(server); | 937 | nfs4_renewd_prepare_shutdown(server); |
938 | nfs_free_server(server); | ||
939 | } | ||
940 | |||
941 | /* | ||
942 | * Clone an NFS4 server record on xdev traversal (FSID-change) | ||
943 | */ | ||
944 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, | ||
945 | const char *dev_name, void *raw_data, | ||
946 | struct vfsmount *mnt) | ||
947 | { | ||
948 | struct nfs_clone_mount *data = raw_data; | ||
949 | struct super_block *s; | ||
950 | struct nfs_server *server; | ||
951 | struct dentry *mntroot; | ||
952 | int error; | ||
953 | |||
954 | dprintk("--> nfs4_xdev_get_sb()\n"); | ||
955 | |||
956 | /* create a new volume representation */ | ||
957 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); | ||
958 | if (IS_ERR(server)) { | ||
959 | error = PTR_ERR(server); | ||
960 | goto out_err_noserver; | ||
961 | } | ||
962 | |||
963 | /* Get a superblock - note that we may end up sharing one that already exists */ | ||
964 | s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); | ||
965 | if (IS_ERR(s)) { | ||
966 | error = PTR_ERR(s); | ||
967 | goto out_err_nosb; | ||
968 | } | ||
1406 | 969 | ||
1407 | if (server->client != NULL && !IS_ERR(server->client)) | 970 | if (s->s_fs_info != server) { |
1408 | rpc_shutdown_client(server->client); | 971 | nfs_free_server(server); |
972 | server = NULL; | ||
973 | } | ||
1409 | 974 | ||
1410 | destroy_nfsv4_state(server); | 975 | if (!s->s_root) { |
976 | /* initial superblock/root creation */ | ||
977 | s->s_flags = flags; | ||
978 | nfs4_clone_super(s, data->sb); | ||
979 | } | ||
980 | |||
981 | mntroot = nfs4_get_root(s, data->fh); | ||
982 | if (IS_ERR(mntroot)) { | ||
983 | error = PTR_ERR(mntroot); | ||
984 | goto error_splat_super; | ||
985 | } | ||
1411 | 986 | ||
1412 | rpciod_down(); | 987 | s->s_flags |= MS_ACTIVE; |
988 | mnt->mnt_sb = s; | ||
989 | mnt->mnt_root = mntroot; | ||
990 | |||
991 | dprintk("<-- nfs4_xdev_get_sb() = 0\n"); | ||
992 | return 0; | ||
993 | |||
994 | out_err_nosb: | ||
995 | nfs_free_server(server); | ||
996 | out_err_noserver: | ||
997 | dprintk("<-- nfs4_xdev_get_sb() = %d [error]\n", error); | ||
998 | return error; | ||
1413 | 999 | ||
1414 | nfs_free_iostats(server->io_stats); | 1000 | error_splat_super: |
1415 | kfree(server->hostname); | 1001 | up_write(&s->s_umount); |
1416 | kfree(server); | 1002 | deactivate_super(s); |
1417 | nfs_release_automount_timer(); | 1003 | dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error); |
1004 | return error; | ||
1418 | } | 1005 | } |
1419 | 1006 | ||
1420 | /* | 1007 | /* |
1421 | * Constructs the SERVER-side path | 1008 | * Create an NFS4 server record on referral traversal |
1422 | */ | 1009 | */ |
1423 | static inline char *nfs4_dup_path(const struct dentry *dentry) | 1010 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, |
1011 | const char *dev_name, void *raw_data, | ||
1012 | struct vfsmount *mnt) | ||
1424 | { | 1013 | { |
1425 | char *page = (char *) __get_free_page(GFP_USER); | 1014 | struct nfs_clone_mount *data = raw_data; |
1426 | char *path; | 1015 | struct super_block *s; |
1016 | struct nfs_server *server; | ||
1017 | struct dentry *mntroot; | ||
1018 | struct nfs_fh mntfh; | ||
1019 | int error; | ||
1427 | 1020 | ||
1428 | path = nfs4_path(dentry, page, PAGE_SIZE); | 1021 | dprintk("--> nfs4_referral_get_sb()\n"); |
1429 | if (!IS_ERR(path)) { | ||
1430 | int len = PAGE_SIZE + page - path; | ||
1431 | char *tmp = path; | ||
1432 | 1022 | ||
1433 | path = kmalloc(len, GFP_KERNEL); | 1023 | /* create a new volume representation */ |
1434 | if (path) | 1024 | server = nfs4_create_referral_server(data, &mntfh); |
1435 | memcpy(path, tmp, len); | 1025 | if (IS_ERR(server)) { |
1436 | else | 1026 | error = PTR_ERR(server); |
1437 | path = ERR_PTR(-ENOMEM); | 1027 | goto out_err_noserver; |
1438 | } | 1028 | } |
1439 | free_page((unsigned long)page); | ||
1440 | return path; | ||
1441 | } | ||
1442 | 1029 | ||
1443 | static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data) | 1030 | /* Get a superblock - note that we may end up sharing one that already exists */ |
1444 | { | 1031 | s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); |
1445 | const struct dentry *dentry = data->dentry; | 1032 | if (IS_ERR(s)) { |
1446 | struct nfs4_client *clp = server->nfs4_state; | 1033 | error = PTR_ERR(s); |
1447 | struct super_block *sb; | 1034 | goto out_err_nosb; |
1448 | |||
1449 | server->fsid = data->fattr->fsid; | ||
1450 | nfs_copy_fh(&server->fh, data->fh); | ||
1451 | server->mnt_path = nfs4_dup_path(dentry); | ||
1452 | if (IS_ERR(server->mnt_path)) { | ||
1453 | sb = (struct super_block *)server->mnt_path; | ||
1454 | goto err; | ||
1455 | } | 1035 | } |
1456 | sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server); | ||
1457 | if (IS_ERR(sb) || sb->s_root) | ||
1458 | goto free_path; | ||
1459 | nfs4_server_capabilities(server, &server->fh); | ||
1460 | |||
1461 | down_write(&clp->cl_sem); | ||
1462 | atomic_inc(&clp->cl_count); | ||
1463 | list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); | ||
1464 | up_write(&clp->cl_sem); | ||
1465 | return sb; | ||
1466 | free_path: | ||
1467 | kfree(server->mnt_path); | ||
1468 | err: | ||
1469 | server->mnt_path = NULL; | ||
1470 | return sb; | ||
1471 | } | ||
1472 | 1036 | ||
1473 | static int nfs_clone_nfs4_sb(struct file_system_type *fs_type, | 1037 | if (s->s_fs_info != server) { |
1474 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 1038 | nfs_free_server(server); |
1475 | { | 1039 | server = NULL; |
1476 | struct nfs_clone_mount *data = raw_data; | 1040 | } |
1477 | return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt); | ||
1478 | } | ||
1479 | 1041 | ||
1480 | static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data) | 1042 | if (!s->s_root) { |
1481 | { | 1043 | /* initial superblock/root creation */ |
1482 | struct super_block *sb = ERR_PTR(-ENOMEM); | 1044 | s->s_flags = flags; |
1483 | int len; | 1045 | nfs4_fill_super(s); |
1484 | 1046 | } | |
1485 | len = strlen(data->mnt_path) + 1; | ||
1486 | server->mnt_path = kmalloc(len, GFP_KERNEL); | ||
1487 | if (server->mnt_path == NULL) | ||
1488 | goto err; | ||
1489 | memcpy(server->mnt_path, data->mnt_path, len); | ||
1490 | memcpy(&server->addr, data->addr, sizeof(struct sockaddr_in)); | ||
1491 | |||
1492 | sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server); | ||
1493 | if (IS_ERR(sb) || sb->s_root) | ||
1494 | goto free_path; | ||
1495 | return sb; | ||
1496 | free_path: | ||
1497 | kfree(server->mnt_path); | ||
1498 | err: | ||
1499 | server->mnt_path = NULL; | ||
1500 | return sb; | ||
1501 | } | ||
1502 | 1047 | ||
1503 | static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data) | 1048 | mntroot = nfs4_get_root(s, data->fh); |
1504 | { | 1049 | if (IS_ERR(mntroot)) { |
1505 | struct nfs_server *server = NFS_SB(sb); | 1050 | error = PTR_ERR(mntroot); |
1506 | struct rpc_timeout timeparms; | 1051 | goto error_splat_super; |
1507 | int proto, timeo, retrans; | 1052 | } |
1508 | void *err; | ||
1509 | |||
1510 | proto = IPPROTO_TCP; | ||
1511 | /* Since we are following a referral and there may be alternatives, | ||
1512 | set the timeouts and retries to low values */ | ||
1513 | timeo = 2; | ||
1514 | retrans = 1; | ||
1515 | nfs_init_timeout_values(&timeparms, proto, timeo, retrans); | ||
1516 | |||
1517 | server->client = nfs4_create_client(server, &timeparms, proto, data->authflavor); | ||
1518 | if (IS_ERR((err = server->client))) | ||
1519 | goto out_err; | ||
1520 | 1053 | ||
1521 | sb->s_time_gran = 1; | 1054 | s->s_flags |= MS_ACTIVE; |
1522 | sb->s_op = &nfs4_sops; | 1055 | mnt->mnt_sb = s; |
1523 | err = ERR_PTR(nfs_sb_init(sb, data->authflavor)); | 1056 | mnt->mnt_root = mntroot; |
1524 | if (!IS_ERR(err)) | ||
1525 | return server; | ||
1526 | out_err: | ||
1527 | return (struct nfs_server *)err; | ||
1528 | } | ||
1529 | 1057 | ||
1530 | static int nfs_referral_nfs4_sb(struct file_system_type *fs_type, | 1058 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); |
1531 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 1059 | return 0; |
1532 | { | 1060 | |
1533 | struct nfs_clone_mount *data = raw_data; | 1061 | out_err_nosb: |
1534 | return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt); | 1062 | nfs_free_server(server); |
1063 | out_err_noserver: | ||
1064 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); | ||
1065 | return error; | ||
1066 | |||
1067 | error_splat_super: | ||
1068 | up_write(&s->s_umount); | ||
1069 | deactivate_super(s); | ||
1070 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); | ||
1071 | return error; | ||
1535 | } | 1072 | } |
1536 | 1073 | ||
1537 | #endif | 1074 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 7084ac9a6455..c12effb46fe5 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -396,6 +396,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
396 | out: | 396 | out: |
397 | clear_bit(BDI_write_congested, &bdi->state); | 397 | clear_bit(BDI_write_congested, &bdi->state); |
398 | wake_up_all(&nfs_write_congestion); | 398 | wake_up_all(&nfs_write_congestion); |
399 | writeback_congestion_end(); | ||
399 | return err; | 400 | return err; |
400 | } | 401 | } |
401 | 402 | ||
@@ -1252,7 +1253,13 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1252 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", | 1253 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", |
1253 | task->tk_pid, task->tk_status); | 1254 | task->tk_pid, task->tk_status); |
1254 | 1255 | ||
1255 | /* Call the NFS version-specific code */ | 1256 | /* |
1257 | * ->write_done will attempt to use post-op attributes to detect | ||
1258 | * conflicting writes by other clients. A strict interpretation | ||
1259 | * of close-to-open would allow us to continue caching even if | ||
1260 | * another writer had changed the file, but some applications | ||
1261 | * depend on tighter cache coherency when writing. | ||
1262 | */ | ||
1256 | status = NFS_PROTO(data->inode)->write_done(task, data); | 1263 | status = NFS_PROTO(data->inode)->write_done(task, data); |
1257 | if (status != 0) | 1264 | if (status != 0) |
1258 | return status; | 1265 | return status; |
@@ -1273,7 +1280,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1273 | if (time_before(complain, jiffies)) { | 1280 | if (time_before(complain, jiffies)) { |
1274 | dprintk("NFS: faulty NFS server %s:" | 1281 | dprintk("NFS: faulty NFS server %s:" |
1275 | " (committed = %d) != (stable = %d)\n", | 1282 | " (committed = %d) != (stable = %d)\n", |
1276 | NFS_SERVER(data->inode)->hostname, | 1283 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, |
1277 | resp->verf->committed, argp->stable); | 1284 | resp->verf->committed, argp->stable); |
1278 | complain = jiffies + 300 * HZ; | 1285 | complain = jiffies + 300 * HZ; |
1279 | } | 1286 | } |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 54b37b1d2e3a..8583d99ee740 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -375,16 +375,28 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
375 | { | 375 | { |
376 | struct sockaddr_in addr; | 376 | struct sockaddr_in addr; |
377 | struct nfs4_callback *cb = &clp->cl_callback; | 377 | struct nfs4_callback *cb = &clp->cl_callback; |
378 | struct rpc_timeout timeparms; | 378 | struct rpc_timeout timeparms = { |
379 | struct rpc_xprt * xprt; | 379 | .to_initval = (NFSD_LEASE_TIME/4) * HZ, |
380 | .to_retries = 5, | ||
381 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, | ||
382 | .to_exponential = 1, | ||
383 | }; | ||
380 | struct rpc_program * program = &cb->cb_program; | 384 | struct rpc_program * program = &cb->cb_program; |
381 | struct rpc_stat * stat = &cb->cb_stat; | 385 | struct rpc_create_args args = { |
382 | struct rpc_clnt * clnt; | 386 | .protocol = IPPROTO_TCP, |
387 | .address = (struct sockaddr *)&addr, | ||
388 | .addrsize = sizeof(addr), | ||
389 | .timeout = &timeparms, | ||
390 | .servername = clp->cl_name.data, | ||
391 | .program = program, | ||
392 | .version = nfs_cb_version[1]->number, | ||
393 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ | ||
394 | .flags = (RPC_CLNT_CREATE_NOPING), | ||
395 | }; | ||
383 | struct rpc_message msg = { | 396 | struct rpc_message msg = { |
384 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 397 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], |
385 | .rpc_argp = clp, | 398 | .rpc_argp = clp, |
386 | }; | 399 | }; |
387 | char hostname[32]; | ||
388 | int status; | 400 | int status; |
389 | 401 | ||
390 | if (atomic_read(&cb->cb_set)) | 402 | if (atomic_read(&cb->cb_set)) |
@@ -396,51 +408,27 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
396 | addr.sin_port = htons(cb->cb_port); | 408 | addr.sin_port = htons(cb->cb_port); |
397 | addr.sin_addr.s_addr = htonl(cb->cb_addr); | 409 | addr.sin_addr.s_addr = htonl(cb->cb_addr); |
398 | 410 | ||
399 | /* Initialize timeout */ | ||
400 | timeparms.to_initval = (NFSD_LEASE_TIME/4) * HZ; | ||
401 | timeparms.to_retries = 0; | ||
402 | timeparms.to_maxval = (NFSD_LEASE_TIME/2) * HZ; | ||
403 | timeparms.to_exponential = 1; | ||
404 | |||
405 | /* Create RPC transport */ | ||
406 | xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms); | ||
407 | if (IS_ERR(xprt)) { | ||
408 | dprintk("NFSD: couldn't create callback transport!\n"); | ||
409 | goto out_err; | ||
410 | } | ||
411 | |||
412 | /* Initialize rpc_program */ | 411 | /* Initialize rpc_program */ |
413 | program->name = "nfs4_cb"; | 412 | program->name = "nfs4_cb"; |
414 | program->number = cb->cb_prog; | 413 | program->number = cb->cb_prog; |
415 | program->nrvers = ARRAY_SIZE(nfs_cb_version); | 414 | program->nrvers = ARRAY_SIZE(nfs_cb_version); |
416 | program->version = nfs_cb_version; | 415 | program->version = nfs_cb_version; |
417 | program->stats = stat; | 416 | program->stats = &cb->cb_stat; |
418 | 417 | ||
419 | /* Initialize rpc_stat */ | 418 | /* Initialize rpc_stat */ |
420 | memset(stat, 0, sizeof(struct rpc_stat)); | 419 | memset(program->stats, 0, sizeof(cb->cb_stat)); |
421 | stat->program = program; | 420 | program->stats->program = program; |
422 | 421 | ||
423 | /* Create RPC client | 422 | /* Create RPC client */ |
424 | * | 423 | cb->cb_client = rpc_create(&args); |
425 | * XXX AUTH_UNIX only - need AUTH_GSS.... | 424 | if (!cb->cb_client) { |
426 | */ | ||
427 | sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr)); | ||
428 | clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); | ||
429 | if (IS_ERR(clnt)) { | ||
430 | dprintk("NFSD: couldn't create callback client\n"); | 425 | dprintk("NFSD: couldn't create callback client\n"); |
431 | goto out_err; | 426 | goto out_err; |
432 | } | 427 | } |
433 | clnt->cl_intr = 0; | ||
434 | clnt->cl_softrtry = 1; | ||
435 | 428 | ||
436 | /* Kick rpciod, put the call on the wire. */ | 429 | /* Kick rpciod, put the call on the wire. */ |
437 | 430 | if (rpciod_up() != 0) | |
438 | if (rpciod_up() != 0) { | ||
439 | dprintk("nfsd: couldn't start rpciod for callbacks!\n"); | ||
440 | goto out_clnt; | 431 | goto out_clnt; |
441 | } | ||
442 | |||
443 | cb->cb_client = clnt; | ||
444 | 432 | ||
445 | /* the task holds a reference to the nfs4_client struct */ | 433 | /* the task holds a reference to the nfs4_client struct */ |
446 | atomic_inc(&clp->cl_count); | 434 | atomic_inc(&clp->cl_count); |
@@ -448,7 +436,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
448 | msg.rpc_cred = nfsd4_lookupcred(clp,0); | 436 | msg.rpc_cred = nfsd4_lookupcred(clp,0); |
449 | if (IS_ERR(msg.rpc_cred)) | 437 | if (IS_ERR(msg.rpc_cred)) |
450 | goto out_rpciod; | 438 | goto out_rpciod; |
451 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); | 439 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); |
452 | put_rpccred(msg.rpc_cred); | 440 | put_rpccred(msg.rpc_cred); |
453 | 441 | ||
454 | if (status != 0) { | 442 | if (status != 0) { |
@@ -462,7 +450,7 @@ out_rpciod: | |||
462 | rpciod_down(); | 450 | rpciod_down(); |
463 | cb->cb_client = NULL; | 451 | cb->cb_client = NULL; |
464 | out_clnt: | 452 | out_clnt: |
465 | rpc_shutdown_client(clnt); | 453 | rpc_shutdown_client(cb->cb_client); |
466 | out_err: | 454 | out_err: |
467 | dprintk("NFSD: warning: no callback path to client %.*s\n", | 455 | dprintk("NFSD: warning: no callback path to client %.*s\n", |
468 | (int)clp->cl_name.len, clp->cl_name.data); | 456 | (int)clp->cl_name.len, clp->cl_name.data); |