diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/lockd/clntproc.c | 9 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 4 | ||||
-rw-r--r-- | fs/nfs/client.c | 18 | ||||
-rw-r--r-- | fs/nfs/dir.c | 37 | ||||
-rw-r--r-- | fs/nfs/direct.c | 8 | ||||
-rw-r--r-- | fs/nfs/getroot.c | 11 | ||||
-rw-r--r-- | fs/nfs/inode.c | 50 | ||||
-rw-r--r-- | fs/nfs/internal.h | 4 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 24 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 16 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 60 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 2 | ||||
-rw-r--r-- | fs/nfs/proc.c | 30 | ||||
-rw-r--r-- | fs/nfs/read.c | 109 | ||||
-rw-r--r-- | fs/nfs/super.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 91 |
17 files changed, 134 insertions, 343 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 0b4acc1c5e7d..a5c019e1a447 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -361,7 +361,6 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message * | |||
361 | { | 361 | { |
362 | struct nlm_host *host = req->a_host; | 362 | struct nlm_host *host = req->a_host; |
363 | struct rpc_clnt *clnt; | 363 | struct rpc_clnt *clnt; |
364 | int status = -ENOLCK; | ||
365 | 364 | ||
366 | dprintk("lockd: call procedure %d on %s (async)\n", | 365 | dprintk("lockd: call procedure %d on %s (async)\n", |
367 | (int)proc, host->h_name); | 366 | (int)proc, host->h_name); |
@@ -373,12 +372,10 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message * | |||
373 | msg->rpc_proc = &clnt->cl_procinfo[proc]; | 372 | msg->rpc_proc = &clnt->cl_procinfo[proc]; |
374 | 373 | ||
375 | /* bootstrap and kick off the async RPC call */ | 374 | /* bootstrap and kick off the async RPC call */ |
376 | status = rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); | 375 | return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); |
377 | if (status == 0) | ||
378 | return 0; | ||
379 | out_err: | 376 | out_err: |
380 | nlm_release_call(req); | 377 | tk_ops->rpc_release(req); |
381 | return status; | 378 | return -ENOLCK; |
382 | } | 379 | } |
383 | 380 | ||
384 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 381 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index c7db0a5bccdc..cf51f849e76c 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -593,9 +593,7 @@ callback: | |||
593 | 593 | ||
594 | /* Call the client */ | 594 | /* Call the client */ |
595 | kref_get(&block->b_count); | 595 | kref_get(&block->b_count); |
596 | if (nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, | 596 | nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops); |
597 | &nlmsvc_grant_ops) < 0) | ||
598 | nlmsvc_release_block(block); | ||
599 | } | 597 | } |
600 | 598 | ||
601 | /* | 599 | /* |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ae9f36e393cf..2190e6c2792e 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -394,7 +394,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
394 | static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | 394 | static int nfs_create_rpc_client(struct nfs_client *clp, int proto, |
395 | unsigned int timeo, | 395 | unsigned int timeo, |
396 | unsigned int retrans, | 396 | unsigned int retrans, |
397 | rpc_authflavor_t flavor) | 397 | rpc_authflavor_t flavor, |
398 | int flags) | ||
398 | { | 399 | { |
399 | struct rpc_timeout timeparms; | 400 | struct rpc_timeout timeparms; |
400 | struct rpc_clnt *clnt = NULL; | 401 | struct rpc_clnt *clnt = NULL; |
@@ -407,6 +408,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | |||
407 | .program = &nfs_program, | 408 | .program = &nfs_program, |
408 | .version = clp->rpc_ops->version, | 409 | .version = clp->rpc_ops->version, |
409 | .authflavor = flavor, | 410 | .authflavor = flavor, |
411 | .flags = flags, | ||
410 | }; | 412 | }; |
411 | 413 | ||
412 | if (!IS_ERR(clp->cl_rpcclient)) | 414 | if (!IS_ERR(clp->cl_rpcclient)) |
@@ -548,7 +550,7 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data * | |||
548 | * - RFC 2623, sec 2.3.2 | 550 | * - RFC 2623, sec 2.3.2 |
549 | */ | 551 | */ |
550 | error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans, | 552 | error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans, |
551 | RPC_AUTH_UNIX); | 553 | RPC_AUTH_UNIX, 0); |
552 | if (error < 0) | 554 | if (error < 0) |
553 | goto error; | 555 | goto error; |
554 | nfs_mark_client_ready(clp, NFS_CS_READY); | 556 | nfs_mark_client_ready(clp, NFS_CS_READY); |
@@ -868,7 +870,8 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
868 | /* Check NFS protocol revision and initialize RPC op vector */ | 870 | /* Check NFS protocol revision and initialize RPC op vector */ |
869 | clp->rpc_ops = &nfs_v4_clientops; | 871 | clp->rpc_ops = &nfs_v4_clientops; |
870 | 872 | ||
871 | error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour); | 873 | error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour, |
874 | RPC_CLNT_CREATE_DISCRTRY); | ||
872 | if (error < 0) | 875 | if (error < 0) |
873 | goto error; | 876 | goto error; |
874 | memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); | 877 | memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); |
@@ -1030,7 +1033,7 @@ error: | |||
1030 | * Create an NFS4 referral server record | 1033 | * Create an NFS4 referral server record |
1031 | */ | 1034 | */ |
1032 | struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | 1035 | struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, |
1033 | struct nfs_fh *fh) | 1036 | struct nfs_fh *mntfh) |
1034 | { | 1037 | { |
1035 | struct nfs_client *parent_client; | 1038 | struct nfs_client *parent_client; |
1036 | struct nfs_server *server, *parent_server; | 1039 | struct nfs_server *server, *parent_server; |
@@ -1069,8 +1072,13 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1069 | BUG_ON(!server->nfs_client->rpc_ops); | 1072 | BUG_ON(!server->nfs_client->rpc_ops); |
1070 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1073 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
1071 | 1074 | ||
1075 | /* Probe the root fh to retrieve its FSID and filehandle */ | ||
1076 | error = nfs4_path_walk(server, mntfh, data->mnt_path); | ||
1077 | if (error < 0) | ||
1078 | goto error; | ||
1079 | |||
1072 | /* probe the filesystem info for this server filesystem */ | 1080 | /* probe the filesystem info for this server filesystem */ |
1073 | error = nfs_probe_fsinfo(server, fh, &fattr); | 1081 | error = nfs_probe_fsinfo(server, mntfh, &fattr); |
1074 | if (error < 0) | 1082 | if (error < 0) |
1075 | goto error; | 1083 | goto error; |
1076 | 1084 | ||
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f03a770bacb0..92d8ec859e22 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -637,7 +637,7 @@ int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) | |||
637 | * In the case it has, we assume that the dentries are untrustworthy | 637 | * In the case it has, we assume that the dentries are untrustworthy |
638 | * and may need to be looked up again. | 638 | * and may need to be looked up again. |
639 | */ | 639 | */ |
640 | static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry) | 640 | static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) |
641 | { | 641 | { |
642 | if (IS_ROOT(dentry)) | 642 | if (IS_ROOT(dentry)) |
643 | return 1; | 643 | return 1; |
@@ -652,6 +652,12 @@ static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) | |||
652 | dentry->d_fsdata = (void *)verf; | 652 | dentry->d_fsdata = (void *)verf; |
653 | } | 653 | } |
654 | 654 | ||
655 | static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf) | ||
656 | { | ||
657 | if (time_after(verf, (unsigned long)dentry->d_fsdata)) | ||
658 | nfs_set_verifier(dentry, verf); | ||
659 | } | ||
660 | |||
655 | /* | 661 | /* |
656 | * Whenever an NFS operation succeeds, we know that the dentry | 662 | * Whenever an NFS operation succeeds, we know that the dentry |
657 | * is valid, so we update the revalidation timestamp. | 663 | * is valid, so we update the revalidation timestamp. |
@@ -785,7 +791,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
785 | goto out_bad; | 791 | goto out_bad; |
786 | 792 | ||
787 | nfs_renew_times(dentry); | 793 | nfs_renew_times(dentry); |
788 | nfs_set_verifier(dentry, verifier); | 794 | nfs_refresh_verifier(dentry, verifier); |
789 | out_valid: | 795 | out_valid: |
790 | unlock_kernel(); | 796 | unlock_kernel(); |
791 | dput(parent); | 797 | dput(parent); |
@@ -1085,7 +1091,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1085 | verifier = nfs_save_change_attribute(dir); | 1091 | verifier = nfs_save_change_attribute(dir); |
1086 | ret = nfs4_open_revalidate(dir, dentry, openflags, nd); | 1092 | ret = nfs4_open_revalidate(dir, dentry, openflags, nd); |
1087 | if (!ret) | 1093 | if (!ret) |
1088 | nfs_set_verifier(dentry, verifier); | 1094 | nfs_refresh_verifier(dentry, verifier); |
1089 | unlock_kernel(); | 1095 | unlock_kernel(); |
1090 | out: | 1096 | out: |
1091 | dput(parent); | 1097 | dput(parent); |
@@ -1123,8 +1129,21 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) | |||
1123 | } | 1129 | } |
1124 | name.hash = full_name_hash(name.name, name.len); | 1130 | name.hash = full_name_hash(name.name, name.len); |
1125 | dentry = d_lookup(parent, &name); | 1131 | dentry = d_lookup(parent, &name); |
1126 | if (dentry != NULL) | 1132 | if (dentry != NULL) { |
1127 | return dentry; | 1133 | /* Is this a positive dentry that matches the readdir info? */ |
1134 | if (dentry->d_inode != NULL && | ||
1135 | (NFS_FILEID(dentry->d_inode) == entry->ino || | ||
1136 | d_mountpoint(dentry))) { | ||
1137 | if (!desc->plus || entry->fh->size == 0) | ||
1138 | return dentry; | ||
1139 | if (nfs_compare_fh(NFS_FH(dentry->d_inode), | ||
1140 | entry->fh) == 0) | ||
1141 | goto out_renew; | ||
1142 | } | ||
1143 | /* No, so d_drop to allow one to be created */ | ||
1144 | d_drop(dentry); | ||
1145 | dput(dentry); | ||
1146 | } | ||
1128 | if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR)) | 1147 | if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR)) |
1129 | return NULL; | 1148 | return NULL; |
1130 | /* Note: caller is already holding the dir->i_mutex! */ | 1149 | /* Note: caller is already holding the dir->i_mutex! */ |
@@ -1149,6 +1168,10 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) | |||
1149 | nfs_renew_times(dentry); | 1168 | nfs_renew_times(dentry); |
1150 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1169 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1151 | return dentry; | 1170 | return dentry; |
1171 | out_renew: | ||
1172 | nfs_renew_times(dentry); | ||
1173 | nfs_refresh_verifier(dentry, nfs_save_change_attribute(dir)); | ||
1174 | return dentry; | ||
1152 | } | 1175 | } |
1153 | 1176 | ||
1154 | /* | 1177 | /* |
@@ -1443,6 +1466,8 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1443 | if (atomic_read(&dentry->d_count) > 1) { | 1466 | if (atomic_read(&dentry->d_count) > 1) { |
1444 | spin_unlock(&dentry->d_lock); | 1467 | spin_unlock(&dentry->d_lock); |
1445 | spin_unlock(&dcache_lock); | 1468 | spin_unlock(&dcache_lock); |
1469 | /* Start asynchronous writeout of the inode */ | ||
1470 | write_inode_now(dentry->d_inode, 0); | ||
1446 | error = nfs_sillyrename(dir, dentry); | 1471 | error = nfs_sillyrename(dir, dentry); |
1447 | unlock_kernel(); | 1472 | unlock_kernel(); |
1448 | return error; | 1473 | return error; |
@@ -1684,7 +1709,7 @@ out: | |||
1684 | if (!error) { | 1709 | if (!error) { |
1685 | d_move(old_dentry, new_dentry); | 1710 | d_move(old_dentry, new_dentry); |
1686 | nfs_renew_times(new_dentry); | 1711 | nfs_renew_times(new_dentry); |
1687 | nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir)); | 1712 | nfs_refresh_verifier(new_dentry, nfs_save_change_attribute(new_dir)); |
1688 | } | 1713 | } |
1689 | 1714 | ||
1690 | /* new dentry created? */ | 1715 | /* new dentry created? */ |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index bd21d7fde650..b1c98ea39b72 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -309,7 +309,8 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |||
309 | 309 | ||
310 | rpc_execute(&data->task); | 310 | rpc_execute(&data->task); |
311 | 311 | ||
312 | dfprintk(VFS, "NFS: %5u initiated direct read call (req %s/%Ld, %zu bytes @ offset %Lu)\n", | 312 | dprintk("NFS: %5u initiated direct read call " |
313 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | ||
313 | data->task.tk_pid, | 314 | data->task.tk_pid, |
314 | inode->i_sb->s_id, | 315 | inode->i_sb->s_id, |
315 | (long long)NFS_FILEID(inode), | 316 | (long long)NFS_FILEID(inode), |
@@ -639,7 +640,8 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l | |||
639 | 640 | ||
640 | rpc_execute(&data->task); | 641 | rpc_execute(&data->task); |
641 | 642 | ||
642 | dfprintk(VFS, "NFS: %5u initiated direct write call (req %s/%Ld, %zu bytes @ offset %Lu)\n", | 643 | dprintk("NFS: %5u initiated direct write call " |
644 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | ||
643 | data->task.tk_pid, | 645 | data->task.tk_pid, |
644 | inode->i_sb->s_id, | 646 | inode->i_sb->s_id, |
645 | (long long)NFS_FILEID(inode), | 647 | (long long)NFS_FILEID(inode), |
@@ -797,7 +799,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
797 | const char __user *buf = iov[0].iov_base; | 799 | const char __user *buf = iov[0].iov_base; |
798 | size_t count = iov[0].iov_len; | 800 | size_t count = iov[0].iov_len; |
799 | 801 | ||
800 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", | 802 | dprintk("nfs: direct write(%s/%s, %lu@%Ld)\n", |
801 | file->f_path.dentry->d_parent->d_name.name, | 803 | file->f_path.dentry->d_parent->d_name.name, |
802 | file->f_path.dentry->d_name.name, | 804 | file->f_path.dentry->d_name.name, |
803 | (unsigned long) count, (long long) pos); | 805 | (unsigned long) count, (long long) pos); |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 8391bd7a83ce..6ef268f7c300 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -135,17 +135,15 @@ int nfs4_path_walk(struct nfs_server *server, | |||
135 | struct nfs_fh lastfh; | 135 | struct nfs_fh lastfh; |
136 | struct qstr name; | 136 | struct qstr name; |
137 | int ret; | 137 | int ret; |
138 | //int referral_count = 0; | ||
139 | 138 | ||
140 | dprintk("--> nfs4_path_walk(,,%s)\n", path); | 139 | dprintk("--> nfs4_path_walk(,,%s)\n", path); |
141 | 140 | ||
142 | fsinfo.fattr = &fattr; | 141 | fsinfo.fattr = &fattr; |
143 | nfs_fattr_init(&fattr); | 142 | nfs_fattr_init(&fattr); |
144 | 143 | ||
145 | if (*path++ != '/') { | 144 | /* Eat leading slashes */ |
146 | dprintk("nfs4_get_root: Path does not begin with a slash\n"); | 145 | while (*path == '/') |
147 | return -EINVAL; | 146 | path++; |
148 | } | ||
149 | 147 | ||
150 | /* Start by getting the root filehandle from the server */ | 148 | /* Start by getting the root filehandle from the server */ |
151 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 149 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
@@ -160,6 +158,7 @@ int nfs4_path_walk(struct nfs_server *server, | |||
160 | return -ENOTDIR; | 158 | return -ENOTDIR; |
161 | } | 159 | } |
162 | 160 | ||
161 | /* FIXME: It is quite valid for the server to return a referral here */ | ||
163 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | 162 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
164 | printk(KERN_ERR "nfs4_get_root:" | 163 | printk(KERN_ERR "nfs4_get_root:" |
165 | " getroot obtained referral\n"); | 164 | " getroot obtained referral\n"); |
@@ -187,6 +186,7 @@ eat_dot_dir: | |||
187 | goto eat_dot_dir; | 186 | goto eat_dot_dir; |
188 | } | 187 | } |
189 | 188 | ||
189 | /* FIXME: Why shouldn't the user be able to use ".." in the path? */ | ||
190 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) | 190 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) |
191 | ) { | 191 | ) { |
192 | printk(KERN_ERR "nfs4_get_root:" | 192 | printk(KERN_ERR "nfs4_get_root:" |
@@ -212,6 +212,7 @@ eat_dot_dir: | |||
212 | return -ENOTDIR; | 212 | return -ENOTDIR; |
213 | } | 213 | } |
214 | 214 | ||
215 | /* FIXME: Referrals are quite valid here too */ | ||
215 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | 216 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
216 | printk(KERN_ERR "nfs4_get_root:" | 217 | printk(KERN_ERR "nfs4_get_root:" |
217 | " lookupfh obtained referral\n"); | 218 | " lookupfh obtained referral\n"); |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d83498282837..af53c02f473b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -65,13 +65,18 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) | |||
65 | 65 | ||
66 | int nfs_write_inode(struct inode *inode, int sync) | 66 | int nfs_write_inode(struct inode *inode, int sync) |
67 | { | 67 | { |
68 | int flags = sync ? FLUSH_SYNC : 0; | ||
69 | int ret; | 68 | int ret; |
70 | 69 | ||
71 | ret = nfs_commit_inode(inode, flags); | 70 | if (sync) { |
72 | if (ret < 0) | 71 | ret = filemap_fdatawait(inode->i_mapping); |
73 | return ret; | 72 | if (ret == 0) |
74 | return 0; | 73 | ret = nfs_commit_inode(inode, FLUSH_SYNC); |
74 | } else | ||
75 | ret = nfs_commit_inode(inode, 0); | ||
76 | if (ret >= 0) | ||
77 | return 0; | ||
78 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
79 | return ret; | ||
75 | } | 80 | } |
76 | 81 | ||
77 | void nfs_clear_inode(struct inode *inode) | 82 | void nfs_clear_inode(struct inode *inode) |
@@ -235,6 +240,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
235 | 240 | ||
236 | if (inode->i_state & I_NEW) { | 241 | if (inode->i_state & I_NEW) { |
237 | struct nfs_inode *nfsi = NFS_I(inode); | 242 | struct nfs_inode *nfsi = NFS_I(inode); |
243 | unsigned long now = jiffies; | ||
238 | 244 | ||
239 | /* We set i_ino for the few things that still rely on it, | 245 | /* We set i_ino for the few things that still rely on it, |
240 | * such as stat(2) */ | 246 | * such as stat(2) */ |
@@ -271,7 +277,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
271 | init_special_inode(inode, inode->i_mode, fattr->rdev); | 277 | init_special_inode(inode, inode->i_mode, fattr->rdev); |
272 | 278 | ||
273 | nfsi->read_cache_jiffies = fattr->time_start; | 279 | nfsi->read_cache_jiffies = fattr->time_start; |
274 | nfsi->last_updated = jiffies; | 280 | nfsi->last_updated = now; |
281 | nfsi->cache_change_attribute = now; | ||
275 | inode->i_atime = fattr->atime; | 282 | inode->i_atime = fattr->atime; |
276 | inode->i_mtime = fattr->mtime; | 283 | inode->i_mtime = fattr->mtime; |
277 | inode->i_ctime = fattr->ctime; | 284 | inode->i_ctime = fattr->ctime; |
@@ -290,7 +297,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
290 | inode->i_blocks = fattr->du.nfs2.blocks; | 297 | inode->i_blocks = fattr->du.nfs2.blocks; |
291 | } | 298 | } |
292 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 299 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
293 | nfsi->attrtimeo_timestamp = jiffies; | 300 | nfsi->attrtimeo_timestamp = now; |
294 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | 301 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); |
295 | nfsi->access_cache = RB_ROOT; | 302 | nfsi->access_cache = RB_ROOT; |
296 | 303 | ||
@@ -783,20 +790,21 @@ void nfs_end_data_update(struct inode *inode) | |||
783 | static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) | 790 | static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) |
784 | { | 791 | { |
785 | struct nfs_inode *nfsi = NFS_I(inode); | 792 | struct nfs_inode *nfsi = NFS_I(inode); |
793 | unsigned long now = jiffies; | ||
786 | 794 | ||
787 | /* If we have atomic WCC data, we may update some attributes */ | 795 | /* If we have atomic WCC data, we may update some attributes */ |
788 | if ((fattr->valid & NFS_ATTR_WCC) != 0) { | 796 | if ((fattr->valid & NFS_ATTR_WCC) != 0) { |
789 | if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) { | 797 | if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) { |
790 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | 798 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); |
791 | nfsi->cache_change_attribute = jiffies; | 799 | nfsi->cache_change_attribute = now; |
792 | } | 800 | } |
793 | if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { | 801 | if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { |
794 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | 802 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); |
795 | nfsi->cache_change_attribute = jiffies; | 803 | nfsi->cache_change_attribute = now; |
796 | } | 804 | } |
797 | if (inode->i_size == fattr->pre_size && nfsi->npages == 0) { | 805 | if (inode->i_size == fattr->pre_size && nfsi->npages == 0) { |
798 | inode->i_size = fattr->size; | 806 | inode->i_size = fattr->size; |
799 | nfsi->cache_change_attribute = jiffies; | 807 | nfsi->cache_change_attribute = now; |
800 | } | 808 | } |
801 | } | 809 | } |
802 | } | 810 | } |
@@ -934,6 +942,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
934 | struct nfs_inode *nfsi = NFS_I(inode); | 942 | struct nfs_inode *nfsi = NFS_I(inode); |
935 | loff_t cur_isize, new_isize; | 943 | loff_t cur_isize, new_isize; |
936 | unsigned int invalid = 0; | 944 | unsigned int invalid = 0; |
945 | unsigned long now = jiffies; | ||
937 | int data_stable; | 946 | int data_stable; |
938 | 947 | ||
939 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", | 948 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", |
@@ -959,7 +968,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
959 | * Update the read time so we don't revalidate too often. | 968 | * Update the read time so we don't revalidate too often. |
960 | */ | 969 | */ |
961 | nfsi->read_cache_jiffies = fattr->time_start; | 970 | nfsi->read_cache_jiffies = fattr->time_start; |
962 | nfsi->last_updated = jiffies; | 971 | nfsi->last_updated = now; |
972 | |||
973 | /* Fix a wraparound issue with nfsi->cache_change_attribute */ | ||
974 | if (time_before(now, nfsi->cache_change_attribute)) | ||
975 | nfsi->cache_change_attribute = now - 600*HZ; | ||
963 | 976 | ||
964 | /* Are we racing with known updates of the metadata on the server? */ | 977 | /* Are we racing with known updates of the metadata on the server? */ |
965 | data_stable = nfs_verify_change_attribute(inode, fattr->time_start); | 978 | data_stable = nfs_verify_change_attribute(inode, fattr->time_start); |
@@ -985,7 +998,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
985 | inode->i_size = new_isize; | 998 | inode->i_size = new_isize; |
986 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 999 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
987 | } | 1000 | } |
988 | nfsi->cache_change_attribute = jiffies; | 1001 | nfsi->cache_change_attribute = now; |
989 | dprintk("NFS: isize change on server for file %s/%ld\n", | 1002 | dprintk("NFS: isize change on server for file %s/%ld\n", |
990 | inode->i_sb->s_id, inode->i_ino); | 1003 | inode->i_sb->s_id, inode->i_ino); |
991 | } | 1004 | } |
@@ -996,14 +1009,14 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
996 | dprintk("NFS: mtime change on server for file %s/%ld\n", | 1009 | dprintk("NFS: mtime change on server for file %s/%ld\n", |
997 | inode->i_sb->s_id, inode->i_ino); | 1010 | inode->i_sb->s_id, inode->i_ino); |
998 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1011 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
999 | nfsi->cache_change_attribute = jiffies; | 1012 | nfsi->cache_change_attribute = now; |
1000 | } | 1013 | } |
1001 | 1014 | ||
1002 | /* If ctime has changed we should definitely clear access+acl caches */ | 1015 | /* If ctime has changed we should definitely clear access+acl caches */ |
1003 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { | 1016 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { |
1004 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1017 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1005 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | 1018 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); |
1006 | nfsi->cache_change_attribute = jiffies; | 1019 | nfsi->cache_change_attribute = now; |
1007 | } | 1020 | } |
1008 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); | 1021 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); |
1009 | 1022 | ||
@@ -1032,18 +1045,18 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1032 | inode->i_sb->s_id, inode->i_ino); | 1045 | inode->i_sb->s_id, inode->i_ino); |
1033 | nfsi->change_attr = fattr->change_attr; | 1046 | nfsi->change_attr = fattr->change_attr; |
1034 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1047 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1035 | nfsi->cache_change_attribute = jiffies; | 1048 | nfsi->cache_change_attribute = now; |
1036 | } | 1049 | } |
1037 | 1050 | ||
1038 | /* Update attrtimeo value if we're out of the unstable period */ | 1051 | /* Update attrtimeo value if we're out of the unstable period */ |
1039 | if (invalid & NFS_INO_INVALID_ATTR) { | 1052 | if (invalid & NFS_INO_INVALID_ATTR) { |
1040 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | 1053 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); |
1041 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 1054 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
1042 | nfsi->attrtimeo_timestamp = jiffies; | 1055 | nfsi->attrtimeo_timestamp = now; |
1043 | } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { | 1056 | } else if (time_after(now, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { |
1044 | if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) | 1057 | if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) |
1045 | nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); | 1058 | nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); |
1046 | nfsi->attrtimeo_timestamp = jiffies; | 1059 | nfsi->attrtimeo_timestamp = now; |
1047 | } | 1060 | } |
1048 | /* Don't invalidate the data if we were to blame */ | 1061 | /* Don't invalidate the data if we were to blame */ |
1049 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) | 1062 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) |
@@ -1122,7 +1135,6 @@ struct inode *nfs_alloc_inode(struct super_block *sb) | |||
1122 | return NULL; | 1135 | return NULL; |
1123 | nfsi->flags = 0UL; | 1136 | nfsi->flags = 0UL; |
1124 | nfsi->cache_validity = 0UL; | 1137 | nfsi->cache_validity = 0UL; |
1125 | nfsi->cache_change_attribute = jiffies; | ||
1126 | #ifdef CONFIG_NFS_V3_ACL | 1138 | #ifdef CONFIG_NFS_V3_ACL |
1127 | nfsi->acl_access = ERR_PTR(-EAGAIN); | 1139 | nfsi->acl_access = ERR_PTR(-EAGAIN); |
1128 | nfsi->acl_default = ERR_PTR(-EAGAIN); | 1140 | nfsi->acl_default = ERR_PTR(-EAGAIN); |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index a28f6ce2e131..6610f2b02077 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -107,10 +107,6 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); | |||
107 | /* nfs4proc.c */ | 107 | /* nfs4proc.c */ |
108 | #ifdef CONFIG_NFS_V4 | 108 | #ifdef CONFIG_NFS_V4 |
109 | extern struct rpc_procinfo nfs4_procedures[]; | 109 | extern struct rpc_procinfo nfs4_procedures[]; |
110 | |||
111 | extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | ||
112 | struct nfs4_fs_locations *fs_locations, | ||
113 | struct page *page); | ||
114 | #endif | 110 | #endif |
115 | 111 | ||
116 | /* dir.c */ | 112 | /* dir.c */ |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index acd8fe9762d3..7d0371e2bad5 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -253,29 +253,6 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, | |||
253 | return status; | 253 | return status; |
254 | } | 254 | } |
255 | 255 | ||
256 | static int nfs3_proc_read(struct nfs_read_data *rdata) | ||
257 | { | ||
258 | int flags = rdata->flags; | ||
259 | struct inode * inode = rdata->inode; | ||
260 | struct nfs_fattr * fattr = rdata->res.fattr; | ||
261 | struct rpc_message msg = { | ||
262 | .rpc_proc = &nfs3_procedures[NFS3PROC_READ], | ||
263 | .rpc_argp = &rdata->args, | ||
264 | .rpc_resp = &rdata->res, | ||
265 | .rpc_cred = rdata->cred, | ||
266 | }; | ||
267 | int status; | ||
268 | |||
269 | dprintk("NFS call read %d @ %Ld\n", rdata->args.count, | ||
270 | (long long) rdata->args.offset); | ||
271 | nfs_fattr_init(fattr); | ||
272 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); | ||
273 | if (status >= 0) | ||
274 | nfs_refresh_inode(inode, fattr); | ||
275 | dprintk("NFS reply read: %d\n", status); | ||
276 | return status; | ||
277 | } | ||
278 | |||
279 | /* | 256 | /* |
280 | * Create a regular file. | 257 | * Create a regular file. |
281 | * For now, we don't implement O_EXCL. | 258 | * For now, we don't implement O_EXCL. |
@@ -855,7 +832,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
855 | .lookup = nfs3_proc_lookup, | 832 | .lookup = nfs3_proc_lookup, |
856 | .access = nfs3_proc_access, | 833 | .access = nfs3_proc_access, |
857 | .readlink = nfs3_proc_readlink, | 834 | .readlink = nfs3_proc_readlink, |
858 | .read = nfs3_proc_read, | ||
859 | .create = nfs3_proc_create, | 835 | .create = nfs3_proc_create, |
860 | .remove = nfs3_proc_remove, | 836 | .remove = nfs3_proc_remove, |
861 | .unlink_setup = nfs3_proc_unlink_setup, | 837 | .unlink_setup = nfs3_proc_unlink_setup, |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index e2341766c4f0..cf3a17eb5c09 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -169,7 +169,7 @@ extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); | |||
169 | 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 *); |
170 | 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 *); |
171 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 171 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
172 | extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | 172 | extern int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, |
173 | struct nfs4_fs_locations *fs_locations, struct page *page); | 173 | struct nfs4_fs_locations *fs_locations, struct page *page); |
174 | 174 | ||
175 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | 175 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index b872779d7cd5..dd5fef20c702 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/vfs.h> | 16 | #include <linux/vfs.h> |
17 | #include <linux/inet.h> | 17 | #include <linux/inet.h> |
18 | #include "internal.h" | 18 | #include "internal.h" |
19 | #include "nfs4_fs.h" | ||
19 | 20 | ||
20 | #define NFSDBG_FACILITY NFSDBG_VFS | 21 | #define NFSDBG_FACILITY NFSDBG_VFS |
21 | 22 | ||
@@ -130,7 +131,6 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
130 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | 131 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, |
131 | }; | 132 | }; |
132 | char *page = NULL, *page2 = NULL; | 133 | char *page = NULL, *page2 = NULL; |
133 | char *devname; | ||
134 | int loc, s, error; | 134 | int loc, s, error; |
135 | 135 | ||
136 | if (locations == NULL || locations->nlocations <= 0) | 136 | if (locations == NULL || locations->nlocations <= 0) |
@@ -154,12 +154,6 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
154 | goto out; | 154 | goto out; |
155 | } | 155 | } |
156 | 156 | ||
157 | devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); | ||
158 | if (IS_ERR(devname)) { | ||
159 | mnt = (struct vfsmount *)devname; | ||
160 | goto out; | ||
161 | } | ||
162 | |||
163 | loc = 0; | 157 | loc = 0; |
164 | while (loc < locations->nlocations && IS_ERR(mnt)) { | 158 | while (loc < locations->nlocations && IS_ERR(mnt)) { |
165 | const struct nfs4_fs_location *location = &locations->locations[loc]; | 159 | const struct nfs4_fs_location *location = &locations->locations[loc]; |
@@ -194,7 +188,11 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
194 | addr.sin_port = htons(NFS_PORT); | 188 | addr.sin_port = htons(NFS_PORT); |
195 | mountdata.addr = &addr; | 189 | mountdata.addr = &addr; |
196 | 190 | ||
197 | mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata); | 191 | snprintf(page, PAGE_SIZE, "%s:%s", |
192 | mountdata.hostname, | ||
193 | mountdata.mnt_path); | ||
194 | |||
195 | mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, &mountdata); | ||
198 | if (!IS_ERR(mnt)) { | 196 | if (!IS_ERR(mnt)) { |
199 | break; | 197 | break; |
200 | } | 198 | } |
@@ -242,7 +240,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr | |||
242 | dprintk("%s: getting locations for %s/%s\n", | 240 | dprintk("%s: getting locations for %s/%s\n", |
243 | __FUNCTION__, parent->d_name.name, dentry->d_name.name); | 241 | __FUNCTION__, parent->d_name.name, dentry->d_name.name); |
244 | 242 | ||
245 | err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); | 243 | err = nfs4_proc_fs_locations(parent->d_inode, &dentry->d_name, fs_locations, page); |
246 | dput(parent); | 244 | dput(parent); |
247 | if (err != 0 || | 245 | if (err != 0 || |
248 | fs_locations->nlocations <= 0 || | 246 | fs_locations->nlocations <= 0 || |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1daee65b517e..f52cf5c33c6c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -1140,7 +1140,6 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1140 | break; | 1140 | break; |
1141 | case -NFS4ERR_STALE_STATEID: | 1141 | case -NFS4ERR_STALE_STATEID: |
1142 | case -NFS4ERR_EXPIRED: | 1142 | case -NFS4ERR_EXPIRED: |
1143 | nfs4_schedule_state_recovery(server->nfs_client); | ||
1144 | break; | 1143 | break; |
1145 | default: | 1144 | default: |
1146 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 1145 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { |
@@ -1424,7 +1423,6 @@ static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fa | |||
1424 | int status = -ENOMEM; | 1423 | int status = -ENOMEM; |
1425 | struct page *page = NULL; | 1424 | struct page *page = NULL; |
1426 | struct nfs4_fs_locations *locations = NULL; | 1425 | struct nfs4_fs_locations *locations = NULL; |
1427 | struct dentry dentry = {}; | ||
1428 | 1426 | ||
1429 | page = alloc_page(GFP_KERNEL); | 1427 | page = alloc_page(GFP_KERNEL); |
1430 | if (page == NULL) | 1428 | if (page == NULL) |
@@ -1433,9 +1431,7 @@ static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fa | |||
1433 | if (locations == NULL) | 1431 | if (locations == NULL) |
1434 | goto out; | 1432 | goto out; |
1435 | 1433 | ||
1436 | dentry.d_name.name = name->name; | 1434 | status = nfs4_proc_fs_locations(dir, name, locations, page); |
1437 | dentry.d_name.len = name->len; | ||
1438 | status = nfs4_proc_fs_locations(dir, &dentry, locations, page); | ||
1439 | if (status != 0) | 1435 | if (status != 0) |
1440 | goto out; | 1436 | goto out; |
1441 | /* Make sure server returned a different fsid for the referral */ | 1437 | /* Make sure server returned a different fsid for the referral */ |
@@ -1737,44 +1733,6 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
1737 | return err; | 1733 | return err; |
1738 | } | 1734 | } |
1739 | 1735 | ||
1740 | static int _nfs4_proc_read(struct nfs_read_data *rdata) | ||
1741 | { | ||
1742 | int flags = rdata->flags; | ||
1743 | struct inode *inode = rdata->inode; | ||
1744 | struct nfs_fattr *fattr = rdata->res.fattr; | ||
1745 | struct nfs_server *server = NFS_SERVER(inode); | ||
1746 | struct rpc_message msg = { | ||
1747 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ], | ||
1748 | .rpc_argp = &rdata->args, | ||
1749 | .rpc_resp = &rdata->res, | ||
1750 | .rpc_cred = rdata->cred, | ||
1751 | }; | ||
1752 | unsigned long timestamp = jiffies; | ||
1753 | int status; | ||
1754 | |||
1755 | dprintk("NFS call read %d @ %Ld\n", rdata->args.count, | ||
1756 | (long long) rdata->args.offset); | ||
1757 | |||
1758 | nfs_fattr_init(fattr); | ||
1759 | status = rpc_call_sync(server->client, &msg, flags); | ||
1760 | if (!status) | ||
1761 | renew_lease(server, timestamp); | ||
1762 | dprintk("NFS reply read: %d\n", status); | ||
1763 | return status; | ||
1764 | } | ||
1765 | |||
1766 | static int nfs4_proc_read(struct nfs_read_data *rdata) | ||
1767 | { | ||
1768 | struct nfs4_exception exception = { }; | ||
1769 | int err; | ||
1770 | do { | ||
1771 | err = nfs4_handle_exception(NFS_SERVER(rdata->inode), | ||
1772 | _nfs4_proc_read(rdata), | ||
1773 | &exception); | ||
1774 | } while (exception.retry); | ||
1775 | return err; | ||
1776 | } | ||
1777 | |||
1778 | /* | 1736 | /* |
1779 | * Got race? | 1737 | * Got race? |
1780 | * We will need to arrange for the VFS layer to provide an atomic open. | 1738 | * We will need to arrange for the VFS layer to provide an atomic open. |
@@ -2753,11 +2711,15 @@ static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp) | |||
2753 | 2711 | ||
2754 | might_sleep(); | 2712 | might_sleep(); |
2755 | 2713 | ||
2714 | rwsem_acquire(&clp->cl_sem.dep_map, 0, 0, _RET_IP_); | ||
2715 | |||
2756 | rpc_clnt_sigmask(clnt, &oldset); | 2716 | rpc_clnt_sigmask(clnt, &oldset); |
2757 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER, | 2717 | res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER, |
2758 | nfs4_wait_bit_interruptible, | 2718 | nfs4_wait_bit_interruptible, |
2759 | TASK_INTERRUPTIBLE); | 2719 | TASK_INTERRUPTIBLE); |
2760 | rpc_clnt_sigunmask(clnt, &oldset); | 2720 | rpc_clnt_sigunmask(clnt, &oldset); |
2721 | |||
2722 | rwsem_release(&clp->cl_sem.dep_map, 1, _RET_IP_); | ||
2761 | return res; | 2723 | return res; |
2762 | } | 2724 | } |
2763 | 2725 | ||
@@ -2996,7 +2958,6 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4 | |||
2996 | switch (err) { | 2958 | switch (err) { |
2997 | case -NFS4ERR_STALE_STATEID: | 2959 | case -NFS4ERR_STALE_STATEID: |
2998 | case -NFS4ERR_EXPIRED: | 2960 | case -NFS4ERR_EXPIRED: |
2999 | nfs4_schedule_state_recovery(server->nfs_client); | ||
3000 | case 0: | 2961 | case 0: |
3001 | return 0; | 2962 | return 0; |
3002 | } | 2963 | } |
@@ -3150,12 +3111,10 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3150 | break; | 3111 | break; |
3151 | case -NFS4ERR_STALE_STATEID: | 3112 | case -NFS4ERR_STALE_STATEID: |
3152 | case -NFS4ERR_EXPIRED: | 3113 | case -NFS4ERR_EXPIRED: |
3153 | nfs4_schedule_state_recovery(calldata->server->nfs_client); | ||
3154 | break; | 3114 | break; |
3155 | default: | 3115 | default: |
3156 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { | 3116 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) |
3157 | rpc_restart_call(task); | 3117 | rpc_restart_call(task); |
3158 | } | ||
3159 | } | 3118 | } |
3160 | } | 3119 | } |
3161 | 3120 | ||
@@ -3585,7 +3544,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | |||
3585 | return len; | 3544 | return len; |
3586 | } | 3545 | } |
3587 | 3546 | ||
3588 | int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | 3547 | int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, |
3589 | struct nfs4_fs_locations *fs_locations, struct page *page) | 3548 | struct nfs4_fs_locations *fs_locations, struct page *page) |
3590 | { | 3549 | { |
3591 | struct nfs_server *server = NFS_SERVER(dir); | 3550 | struct nfs_server *server = NFS_SERVER(dir); |
@@ -3595,7 +3554,7 @@ int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | |||
3595 | }; | 3554 | }; |
3596 | struct nfs4_fs_locations_arg args = { | 3555 | struct nfs4_fs_locations_arg args = { |
3597 | .dir_fh = NFS_FH(dir), | 3556 | .dir_fh = NFS_FH(dir), |
3598 | .name = &dentry->d_name, | 3557 | .name = name, |
3599 | .page = page, | 3558 | .page = page, |
3600 | .bitmask = bitmask, | 3559 | .bitmask = bitmask, |
3601 | }; | 3560 | }; |
@@ -3607,7 +3566,7 @@ int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | |||
3607 | int status; | 3566 | int status; |
3608 | 3567 | ||
3609 | dprintk("%s: start\n", __FUNCTION__); | 3568 | dprintk("%s: start\n", __FUNCTION__); |
3610 | fs_locations->fattr.valid = 0; | 3569 | nfs_fattr_init(&fs_locations->fattr); |
3611 | fs_locations->server = server; | 3570 | fs_locations->server = server; |
3612 | fs_locations->nlocations = 0; | 3571 | fs_locations->nlocations = 0; |
3613 | status = rpc_call_sync(server->client, &msg, 0); | 3572 | status = rpc_call_sync(server->client, &msg, 0); |
@@ -3646,7 +3605,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
3646 | .lookup = nfs4_proc_lookup, | 3605 | .lookup = nfs4_proc_lookup, |
3647 | .access = nfs4_proc_access, | 3606 | .access = nfs4_proc_access, |
3648 | .readlink = nfs4_proc_readlink, | 3607 | .readlink = nfs4_proc_readlink, |
3649 | .read = nfs4_proc_read, | ||
3650 | .create = nfs4_proc_create, | 3608 | .create = nfs4_proc_create, |
3651 | .remove = nfs4_proc_remove, | 3609 | .remove = nfs4_proc_remove, |
3652 | .unlink_setup = nfs4_proc_unlink_setup, | 3610 | .unlink_setup = nfs4_proc_unlink_setup, |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0cf3fa312a33..f02d522fd788 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -387,8 +387,10 @@ static int nfs4_stat_to_errno(int); | |||
387 | decode_putfh_maxsz + \ | 387 | decode_putfh_maxsz + \ |
388 | op_decode_hdr_maxsz + 12) | 388 | op_decode_hdr_maxsz + 12) |
389 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ | 389 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ |
390 | encode_putfh_maxsz + \ | ||
390 | encode_getattr_maxsz) | 391 | encode_getattr_maxsz) |
391 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ | 392 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ |
393 | decode_putfh_maxsz + \ | ||
392 | decode_getattr_maxsz) | 394 | decode_getattr_maxsz) |
393 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ | 395 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ |
394 | encode_putfh_maxsz + \ | 396 | encode_putfh_maxsz + \ |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 560536ad74a4..1dcf56de9482 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -186,35 +186,6 @@ static int nfs_proc_readlink(struct inode *inode, struct page *page, | |||
186 | return status; | 186 | return status; |
187 | } | 187 | } |
188 | 188 | ||
189 | static int nfs_proc_read(struct nfs_read_data *rdata) | ||
190 | { | ||
191 | int flags = rdata->flags; | ||
192 | struct inode * inode = rdata->inode; | ||
193 | struct nfs_fattr * fattr = rdata->res.fattr; | ||
194 | struct rpc_message msg = { | ||
195 | .rpc_proc = &nfs_procedures[NFSPROC_READ], | ||
196 | .rpc_argp = &rdata->args, | ||
197 | .rpc_resp = &rdata->res, | ||
198 | .rpc_cred = rdata->cred, | ||
199 | }; | ||
200 | int status; | ||
201 | |||
202 | dprintk("NFS call read %d @ %Ld\n", rdata->args.count, | ||
203 | (long long) rdata->args.offset); | ||
204 | nfs_fattr_init(fattr); | ||
205 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); | ||
206 | if (status >= 0) { | ||
207 | nfs_refresh_inode(inode, fattr); | ||
208 | /* Emulate the eof flag, which isn't normally needed in NFSv2 | ||
209 | * as it is guaranteed to always return the file attributes | ||
210 | */ | ||
211 | if (rdata->args.offset + rdata->args.count >= fattr->size) | ||
212 | rdata->res.eof = 1; | ||
213 | } | ||
214 | dprintk("NFS reply read: %d\n", status); | ||
215 | return status; | ||
216 | } | ||
217 | |||
218 | static int | 189 | static int |
219 | nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 190 | nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
220 | int flags, struct nameidata *nd) | 191 | int flags, struct nameidata *nd) |
@@ -666,7 +637,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = { | |||
666 | .lookup = nfs_proc_lookup, | 637 | .lookup = nfs_proc_lookup, |
667 | .access = NULL, /* access */ | 638 | .access = NULL, /* access */ |
668 | .readlink = nfs_proc_readlink, | 639 | .readlink = nfs_proc_readlink, |
669 | .read = nfs_proc_read, | ||
670 | .create = nfs_proc_create, | 640 | .create = nfs_proc_create, |
671 | .remove = nfs_proc_remove, | 641 | .remove = nfs_proc_remove, |
672 | .unlink_setup = nfs_proc_unlink_setup, | 642 | .unlink_setup = nfs_proc_unlink_setup, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index a9c26521a9e2..6ab4d5a9edf2 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -5,14 +5,6 @@ | |||
5 | * | 5 | * |
6 | * Partial copy of Linus' read cache modifications to fs/nfs/file.c | 6 | * Partial copy of Linus' read cache modifications to fs/nfs/file.c |
7 | * modified for async RPC by okir@monad.swb.de | 7 | * modified for async RPC by okir@monad.swb.de |
8 | * | ||
9 | * We do an ugly hack here in order to return proper error codes to the | ||
10 | * user program when a read request failed: since generic_file_read | ||
11 | * only checks the return value of inode->i_op->readpage() which is always 0 | ||
12 | * for async RPC, we set the error bit of the page to 1 when an error occurs, | ||
13 | * and make nfs_readpage transmit requests synchronously when encountering this. | ||
14 | * This is only a small problem, though, since we now retry all operations | ||
15 | * within the RPC code when root squashing is suspected. | ||
16 | */ | 8 | */ |
17 | 9 | ||
18 | #include <linux/time.h> | 10 | #include <linux/time.h> |
@@ -122,93 +114,6 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) | |||
122 | } | 114 | } |
123 | } | 115 | } |
124 | 116 | ||
125 | /* | ||
126 | * Read a page synchronously. | ||
127 | */ | ||
128 | static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | ||
129 | struct page *page) | ||
130 | { | ||
131 | unsigned int rsize = NFS_SERVER(inode)->rsize; | ||
132 | unsigned int count = PAGE_CACHE_SIZE; | ||
133 | int result = -ENOMEM; | ||
134 | struct nfs_read_data *rdata; | ||
135 | |||
136 | rdata = nfs_readdata_alloc(count); | ||
137 | if (!rdata) | ||
138 | goto out_unlock; | ||
139 | |||
140 | memset(rdata, 0, sizeof(*rdata)); | ||
141 | rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | ||
142 | rdata->cred = ctx->cred; | ||
143 | rdata->inode = inode; | ||
144 | INIT_LIST_HEAD(&rdata->pages); | ||
145 | rdata->args.fh = NFS_FH(inode); | ||
146 | rdata->args.context = ctx; | ||
147 | rdata->args.pages = &page; | ||
148 | rdata->args.pgbase = 0UL; | ||
149 | rdata->args.count = rsize; | ||
150 | rdata->res.fattr = &rdata->fattr; | ||
151 | |||
152 | dprintk("NFS: nfs_readpage_sync(%p)\n", page); | ||
153 | |||
154 | /* | ||
155 | * This works now because the socket layer never tries to DMA | ||
156 | * into this buffer directly. | ||
157 | */ | ||
158 | do { | ||
159 | if (count < rsize) | ||
160 | rdata->args.count = count; | ||
161 | rdata->res.count = rdata->args.count; | ||
162 | rdata->args.offset = page_offset(page) + rdata->args.pgbase; | ||
163 | |||
164 | dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n", | ||
165 | NFS_SERVER(inode)->nfs_client->cl_hostname, | ||
166 | inode->i_sb->s_id, | ||
167 | (long long)NFS_FILEID(inode), | ||
168 | (unsigned long long)rdata->args.pgbase, | ||
169 | rdata->args.count); | ||
170 | |||
171 | lock_kernel(); | ||
172 | result = NFS_PROTO(inode)->read(rdata); | ||
173 | unlock_kernel(); | ||
174 | |||
175 | /* | ||
176 | * Even if we had a partial success we can't mark the page | ||
177 | * cache valid. | ||
178 | */ | ||
179 | if (result < 0) { | ||
180 | if (result == -EISDIR) | ||
181 | result = -EINVAL; | ||
182 | goto io_error; | ||
183 | } | ||
184 | count -= result; | ||
185 | rdata->args.pgbase += result; | ||
186 | nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, result); | ||
187 | |||
188 | /* Note: result == 0 should only happen if we're caching | ||
189 | * a write that extends the file and punches a hole. | ||
190 | */ | ||
191 | if (rdata->res.eof != 0 || result == 0) | ||
192 | break; | ||
193 | } while (count); | ||
194 | spin_lock(&inode->i_lock); | ||
195 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; | ||
196 | spin_unlock(&inode->i_lock); | ||
197 | |||
198 | if (rdata->res.eof || rdata->res.count == rdata->args.count) { | ||
199 | SetPageUptodate(page); | ||
200 | if (rdata->res.eof && count != 0) | ||
201 | memclear_highpage_flush(page, rdata->args.pgbase, count); | ||
202 | } | ||
203 | result = 0; | ||
204 | |||
205 | io_error: | ||
206 | nfs_readdata_free(rdata); | ||
207 | out_unlock: | ||
208 | unlock_page(page); | ||
209 | return result; | ||
210 | } | ||
211 | |||
212 | static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | 117 | static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, |
213 | struct page *page) | 118 | struct page *page) |
214 | { | 119 | { |
@@ -278,7 +183,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
278 | 183 | ||
279 | data->task.tk_cookie = (unsigned long)inode; | 184 | data->task.tk_cookie = (unsigned long)inode; |
280 | 185 | ||
281 | dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 186 | dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
282 | data->task.tk_pid, | 187 | data->task.tk_pid, |
283 | inode->i_sb->s_id, | 188 | inode->i_sb->s_id, |
284 | (long long)NFS_FILEID(inode), | 189 | (long long)NFS_FILEID(inode), |
@@ -452,7 +357,7 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | |||
452 | { | 357 | { |
453 | int status; | 358 | int status; |
454 | 359 | ||
455 | dprintk("%s: %4d, (status %d)\n", __FUNCTION__, task->tk_pid, | 360 | dprintk("NFS: %s: %5u, (status %d)\n", __FUNCTION__, task->tk_pid, |
456 | task->tk_status); | 361 | task->tk_status); |
457 | 362 | ||
458 | status = NFS_PROTO(data->inode)->read_done(task, data); | 363 | status = NFS_PROTO(data->inode)->read_done(task, data); |
@@ -621,15 +526,9 @@ int nfs_readpage(struct file *file, struct page *page) | |||
621 | } else | 526 | } else |
622 | ctx = get_nfs_open_context((struct nfs_open_context *) | 527 | ctx = get_nfs_open_context((struct nfs_open_context *) |
623 | file->private_data); | 528 | file->private_data); |
624 | if (!IS_SYNC(inode)) { | ||
625 | error = nfs_readpage_async(ctx, inode, page); | ||
626 | goto out; | ||
627 | } | ||
628 | 529 | ||
629 | error = nfs_readpage_sync(ctx, inode, page); | 530 | error = nfs_readpage_async(ctx, inode, page); |
630 | if (error < 0 && IS_SWAPFILE(inode)) | 531 | |
631 | printk("Aiee.. nfs swap-in of page failed!\n"); | ||
632 | out: | ||
633 | put_nfs_open_context(ctx); | 532 | put_nfs_open_context(ctx); |
634 | return error; | 533 | return error; |
635 | 534 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index baa28860ad27..bb516a2cfbaf 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -1045,7 +1045,7 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, | |||
1045 | nfs4_fill_super(s); | 1045 | nfs4_fill_super(s); |
1046 | } | 1046 | } |
1047 | 1047 | ||
1048 | mntroot = nfs4_get_root(s, data->fh); | 1048 | mntroot = nfs4_get_root(s, &mntfh); |
1049 | if (IS_ERR(mntroot)) { | 1049 | if (IS_ERR(mntroot)) { |
1050 | error = PTR_ERR(mntroot); | 1050 | error = PTR_ERR(mntroot); |
1051 | goto error_splat_super; | 1051 | goto error_splat_super; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 345492e78643..febdade91670 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1,47 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/nfs/write.c | 2 | * linux/fs/nfs/write.c |
3 | * | 3 | * |
4 | * Writing file data over NFS. | 4 | * Write file data over NFS. |
5 | * | ||
6 | * We do it like this: When a (user) process wishes to write data to an | ||
7 | * NFS file, a write request is allocated that contains the RPC task data | ||
8 | * plus some info on the page to be written, and added to the inode's | ||
9 | * write chain. If the process writes past the end of the page, an async | ||
10 | * RPC call to write the page is scheduled immediately; otherwise, the call | ||
11 | * is delayed for a few seconds. | ||
12 | * | ||
13 | * Just like readahead, no async I/O is performed if wsize < PAGE_SIZE. | ||
14 | * | ||
15 | * Write requests are kept on the inode's writeback list. Each entry in | ||
16 | * that list references the page (portion) to be written. When the | ||
17 | * cache timeout has expired, the RPC task is woken up, and tries to | ||
18 | * lock the page. As soon as it manages to do so, the request is moved | ||
19 | * from the writeback list to the writelock list. | ||
20 | * | ||
21 | * Note: we must make sure never to confuse the inode passed in the | ||
22 | * write_page request with the one in page->inode. As far as I understand | ||
23 | * it, these are different when doing a swap-out. | ||
24 | * | ||
25 | * To understand everything that goes on here and in the NFS read code, | ||
26 | * one should be aware that a page is locked in exactly one of the following | ||
27 | * cases: | ||
28 | * | ||
29 | * - A write request is in progress. | ||
30 | * - A user process is in generic_file_write/nfs_update_page | ||
31 | * - A user process is in generic_file_read | ||
32 | * | ||
33 | * Also note that because of the way pages are invalidated in | ||
34 | * nfs_revalidate_inode, the following assertions hold: | ||
35 | * | ||
36 | * - If a page is dirty, there will be no read requests (a page will | ||
37 | * not be re-read unless invalidated by nfs_revalidate_inode). | ||
38 | * - If the page is not uptodate, there will be no pending write | ||
39 | * requests, and no process will be in nfs_update_page. | ||
40 | * | ||
41 | * FIXME: Interaction with the vmscan routines is not optimal yet. | ||
42 | * Either vmscan must be made nfs-savvy, or we need a different page | ||
43 | * reclaim concept that supports something like FS-independent | ||
44 | * buffer_heads with a b_ops-> field. | ||
45 | * | 5 | * |
46 | * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> |
47 | */ | 7 | */ |
@@ -79,7 +39,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, | |||
79 | unsigned int, unsigned int); | 39 | unsigned int, unsigned int); |
80 | static void nfs_mark_request_dirty(struct nfs_page *req); | 40 | static void nfs_mark_request_dirty(struct nfs_page *req); |
81 | static int nfs_wait_on_write_congestion(struct address_space *, int); | 41 | static int nfs_wait_on_write_congestion(struct address_space *, int); |
82 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); | ||
83 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); | 42 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); |
84 | static const struct rpc_call_ops nfs_write_partial_ops; | 43 | static const struct rpc_call_ops nfs_write_partial_ops; |
85 | static const struct rpc_call_ops nfs_write_full_ops; | 44 | static const struct rpc_call_ops nfs_write_full_ops; |
@@ -194,6 +153,13 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c | |||
194 | i_size_write(inode, end); | 153 | i_size_write(inode, end); |
195 | } | 154 | } |
196 | 155 | ||
156 | /* A writeback failed: mark the page as bad, and invalidate the page cache */ | ||
157 | static void nfs_set_pageerror(struct page *page) | ||
158 | { | ||
159 | SetPageError(page); | ||
160 | nfs_zap_mapping(page->mapping->host, page->mapping); | ||
161 | } | ||
162 | |||
197 | /* We can set the PG_uptodate flag if we see that a write request | 163 | /* We can set the PG_uptodate flag if we see that a write request |
198 | * covers the full page. | 164 | * covers the full page. |
199 | */ | 165 | */ |
@@ -323,7 +289,7 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc | |||
323 | err = 0; | 289 | err = 0; |
324 | out: | 290 | out: |
325 | if (!wbc->for_writepages) | 291 | if (!wbc->for_writepages) |
326 | nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); | 292 | nfs_flush_mapping(page->mapping, wbc, FLUSH_STABLE|wb_priority(wbc)); |
327 | return err; | 293 | return err; |
328 | } | 294 | } |
329 | 295 | ||
@@ -360,14 +326,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
360 | if (err < 0) | 326 | if (err < 0) |
361 | goto out; | 327 | goto out; |
362 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); | 328 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); |
363 | if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { | 329 | err = 0; |
364 | err = nfs_wait_on_requests(inode, 0, 0); | ||
365 | if (err < 0) | ||
366 | goto out; | ||
367 | } | ||
368 | err = nfs_commit_inode(inode, wb_priority(wbc)); | ||
369 | if (err > 0) | ||
370 | err = 0; | ||
371 | out: | 330 | out: |
372 | clear_bit(BDI_write_congested, &bdi->state); | 331 | clear_bit(BDI_write_congested, &bdi->state); |
373 | wake_up_all(&nfs_write_congestion); | 332 | wake_up_all(&nfs_write_congestion); |
@@ -516,17 +475,6 @@ static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_st | |||
516 | return res; | 475 | return res; |
517 | } | 476 | } |
518 | 477 | ||
519 | static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages) | ||
520 | { | ||
521 | struct nfs_inode *nfsi = NFS_I(inode); | ||
522 | int ret; | ||
523 | |||
524 | spin_lock(&nfsi->req_lock); | ||
525 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | ||
526 | spin_unlock(&nfsi->req_lock); | ||
527 | return ret; | ||
528 | } | ||
529 | |||
530 | static void nfs_cancel_dirty_list(struct list_head *head) | 478 | static void nfs_cancel_dirty_list(struct list_head *head) |
531 | { | 479 | { |
532 | struct nfs_page *req; | 480 | struct nfs_page *req; |
@@ -773,7 +721,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
773 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", | 721 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", |
774 | status, (long long)i_size_read(inode)); | 722 | status, (long long)i_size_read(inode)); |
775 | if (status < 0) | 723 | if (status < 0) |
776 | ClearPageUptodate(page); | 724 | nfs_set_pageerror(page); |
777 | return status; | 725 | return status; |
778 | } | 726 | } |
779 | 727 | ||
@@ -852,7 +800,8 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
852 | data->task.tk_priority = flush_task_priority(how); | 800 | data->task.tk_priority = flush_task_priority(how); |
853 | data->task.tk_cookie = (unsigned long)inode; | 801 | data->task.tk_cookie = (unsigned long)inode; |
854 | 802 | ||
855 | dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 803 | dprintk("NFS: %5u initiated write call " |
804 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", | ||
856 | data->task.tk_pid, | 805 | data->task.tk_pid, |
857 | inode->i_sb->s_id, | 806 | inode->i_sb->s_id, |
858 | (long long)NFS_FILEID(inode), | 807 | (long long)NFS_FILEID(inode), |
@@ -1034,8 +983,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
1034 | return; | 983 | return; |
1035 | 984 | ||
1036 | if (task->tk_status < 0) { | 985 | if (task->tk_status < 0) { |
1037 | ClearPageUptodate(page); | 986 | nfs_set_pageerror(page); |
1038 | SetPageError(page); | ||
1039 | req->wb_context->error = task->tk_status; | 987 | req->wb_context->error = task->tk_status; |
1040 | dprintk(", error = %d\n", task->tk_status); | 988 | dprintk(", error = %d\n", task->tk_status); |
1041 | } else { | 989 | } else { |
@@ -1092,8 +1040,7 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
1092 | (long long)req_offset(req)); | 1040 | (long long)req_offset(req)); |
1093 | 1041 | ||
1094 | if (task->tk_status < 0) { | 1042 | if (task->tk_status < 0) { |
1095 | ClearPageUptodate(page); | 1043 | nfs_set_pageerror(page); |
1096 | SetPageError(page); | ||
1097 | req->wb_context->error = task->tk_status; | 1044 | req->wb_context->error = task->tk_status; |
1098 | end_page_writeback(page); | 1045 | end_page_writeback(page); |
1099 | nfs_inode_remove_request(req); | 1046 | nfs_inode_remove_request(req); |
@@ -1134,7 +1081,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1134 | struct nfs_writeres *resp = &data->res; | 1081 | struct nfs_writeres *resp = &data->res; |
1135 | int status; | 1082 | int status; |
1136 | 1083 | ||
1137 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", | 1084 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
1138 | task->tk_pid, task->tk_status); | 1085 | task->tk_pid, task->tk_status); |
1139 | 1086 | ||
1140 | /* | 1087 | /* |
@@ -1250,7 +1197,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1250 | data->task.tk_priority = flush_task_priority(how); | 1197 | data->task.tk_priority = flush_task_priority(how); |
1251 | data->task.tk_cookie = (unsigned long)inode; | 1198 | data->task.tk_cookie = (unsigned long)inode; |
1252 | 1199 | ||
1253 | dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid); | 1200 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1254 | } | 1201 | } |
1255 | 1202 | ||
1256 | /* | 1203 | /* |
@@ -1291,7 +1238,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1291 | struct nfs_write_data *data = calldata; | 1238 | struct nfs_write_data *data = calldata; |
1292 | struct nfs_page *req; | 1239 | struct nfs_page *req; |
1293 | 1240 | ||
1294 | dprintk("NFS: %4d nfs_commit_done (status %d)\n", | 1241 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", |
1295 | task->tk_pid, task->tk_status); | 1242 | task->tk_pid, task->tk_status); |
1296 | 1243 | ||
1297 | /* Call the NFS version-specific code */ | 1244 | /* Call the NFS version-specific code */ |
@@ -1516,6 +1463,8 @@ int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) | |||
1516 | if (ret < 0) | 1463 | if (ret < 0) |
1517 | goto out; | 1464 | goto out; |
1518 | } | 1465 | } |
1466 | if (!PagePrivate(page)) | ||
1467 | return 0; | ||
1519 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | 1468 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); |
1520 | if (ret >= 0) | 1469 | if (ret >= 0) |
1521 | return 0; | 1470 | return 0; |