1 /*
2 * linux/fs/nfs/sock.c
3 *
4 * Copyright (C) 1992, 1993 Rick Sladkey
5 *
6 * low-level nfs remote procedure call interface
7 *
8 * FIXES
9 *
10 * 2/7/94 James Bottomley and Jon Peatfield DAMTP, Cambridge University
11 *
12 * An xid mismatch no longer causes the request to be trashed.
13 *
14 */
15
16 #include <linux/config.h>
17 #include <linux/sched.h>
18 #include <linux/nfs_fs.h>
19 #include <linux/errno.h>
20 #include <linux/socket.h>
21 #include <linux/fcntl.h>
22 #include <asm/segment.h>
23 #include <linux/in.h>
24 #include <linux/net.h>
25 #include <linux/mm.h>
26
27 /* JEJB/JSP 2/7/94
28 * this must match the value of NFS_SLACK_SPACE in linux/fs/nfs/proc.c
29 * ***FIXME*** should probably put this in nfs_fs.h */
30 #define NFS_SLACK_SPACE 1024
31
32
33 extern struct socket *socki_lookup(struct inode *inode);
34
35 #define _S(nr) (1<<((nr)-1))
36
37 /*
38 * We violate some modularity principles here by poking around
39 * in some socket internals. Besides having to call socket
40 * functions from kernel-space instead of user space, the socket
41 * interface does not lend itself well to being cleanly called
42 * without a file descriptor. Since the nfs calls can run on
43 * behalf of any process, the superblock maintains a file pointer
44 * to the server socket.
45 */
46
47 static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
48 {
49 struct file *file;
50 struct inode *inode;
51 struct socket *sock;
52 unsigned short fs;
53 int result;
54 int xid;
55 int len;
56 select_table wait_table;
57 struct select_table_entry entry;
58 int (*select) (struct inode *, struct file *, int, select_table *);
59 int init_timeout, max_timeout;
60 int timeout;
61 int retrans;
62 int major_timeout_seen;
63 char *server_name;
64 int n;
65 int addrlen;
66 unsigned long old_mask;
67 /* JEJB/JSP 2/7/94
68 * This is for a 4 byte recv of the xid only */
69 int recv_xid;
70
71 xid = start[0];
72 len = ((char *) end) - ((char *) start);
73 file = server->file;
74 inode = file->f_inode;
75 select = file->f_op->select;
76 sock = socki_lookup(inode);
77 if (!sock) {
78 printk("nfs_rpc_call: socki_lookup failed\n");
79 return -EBADF;
80 }
81 init_timeout = server->timeo;
82 max_timeout = NFS_MAX_RPC_TIMEOUT*HZ/10;
83 retrans = server->retrans;
84 major_timeout_seen = 0;
85 server_name = server->hostname;
86 old_mask = current->blocked;
87 current->blocked |= ~(_S(SIGKILL)
88 #if 0
89 | _S(SIGSTOP)
90 #endif
91 | ((server->flags & NFS_MOUNT_INTR)
92 ? ((current->sigaction[SIGINT - 1].sa_handler == SIG_DFL
93 ? _S(SIGINT) : 0)
94 | (current->sigaction[SIGQUIT - 1].sa_handler == SIG_DFL
95 ? _S(SIGQUIT) : 0))
96 : 0));
97 fs = get_fs();
98 set_fs(get_ds());
99 for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) {
100 result = sock->ops->send(sock, (void *) start, len, 0, 0);
101 if (result < 0) {
102 printk("nfs_rpc_call: send error = %d\n", result);
103 break;
104 }
105 re_select:
106 wait_table.nr = 0;
107 wait_table.entry = &entry;
108 current->state = TASK_INTERRUPTIBLE;
109 if (!select(inode, file, SEL_IN, &wait_table)
110 && !select(inode, file, SEL_IN, NULL)) {
111 if (timeout > max_timeout) {
112 /* JEJB/JSP 2/7/94
113 * This is useful to see if the system is
114 * hanging */
115 printk("NFS max timeout reached on %s\n",
116 server_name);
117 timeout = max_timeout;
118 }
119 current->timeout = jiffies + timeout;
120 schedule();
121 remove_wait_queue(entry.wait_address, &entry.wait);
122 current->state = TASK_RUNNING;
123 if (current->signal & ~current->blocked) {
124 current->timeout = 0;
125 result = -ERESTARTSYS;
126 break;
127 }
128 if (!current->timeout) {
129 if (n < retrans)
130 continue;
131 if (server->flags & NFS_MOUNT_SOFT) {
132 printk("NFS server %s not responding, "
133 "timed out\n", server_name);
134 result = -EIO;
135 break;
136 }
137 n = 0;
138 timeout = init_timeout;
139 init_timeout <<= 1;
140 if (!major_timeout_seen) {
141 printk("NFS server %s not responding, "
142 "still trying\n", server_name);
143 }
144 major_timeout_seen = 1;
145 continue;
146 }
147 else
148 current->timeout = 0;
149 }
150 else if (wait_table.nr)
151 remove_wait_queue(entry.wait_address, &entry.wait);
152 current->state = TASK_RUNNING;
153 addrlen = 0;
154 /* JEJB/JSP 2/7/94
155 * Get the xid from the next packet using a peek, so keep it
156 * on the recv queue. If it is wrong, it will be some reply
157 * we don't now need, so discard it */
158 result = sock->ops->recvfrom(sock, (void *)&recv_xid,
159 sizeof(recv_xid), 1, MSG_PEEK,
160 NULL, &addrlen);
161 if (result < 0) {
162 if (result == -EAGAIN) {
163 #if 0
164 printk("nfs_rpc_call: bad select ready\n");
165 #endif
166 goto re_select;
167 }
168 if (result == -ECONNREFUSED) {
169 #if 0
170 printk("nfs_rpc_call: server playing coy\n");
171 #endif
172 goto re_select;
173 }
174 if (result != -ERESTARTSYS) {
175 printk("nfs_rpc_call: recv error = %d\n",
176 -result);
177 }
178 break;
179 }
180 if (recv_xid == xid) {
181 if (major_timeout_seen)
182 printk("NFS server %s OK\n", server_name);
183 break;
184 }
185 /* JEJB/JSP 2/7/94
186 * we have xid mismatch, so discard the packet and start
187 * again. What a hack! but I can't call recvfrom with
188 * a null buffer yet. */
189 (void)sock->ops->recvfrom(sock, (void *)&recv_xid,
190 sizeof(recv_xid), 1, 0, NULL,
191 &addrlen);
192 #if 0
193 printk("nfs_rpc_call: XID mismatch\n");
194 #endif
195 }
196 /* JEJB/JSP 2/7/94
197 *
198 * we have the correct xid, so read into the correct place and
199 * return it
200 *
201 * Here we need to know the size given to alloc, server->wsize for
202 * writes or server->rsize for reads. In practice these are the
203 * same.
204 *
205 * If they are not the same then a reply to a write request will be
206 * a small acknowledgement, so even if wsize < rsize we should never
207 * cause data to be written past the end of the buffer (unless some
208 * brain damaged implementation sends out a large write acknowledge).
209 *
210 * FIXME: I should really know how big a packet was alloc'd --
211 * should pass it to do_nfs_rpc. */
212 result=sock->ops->recvfrom(sock, (void *)start,
213 server->rsize + NFS_SLACK_SPACE, 1, 0, NULL,
214 &addrlen);
215 current->blocked = old_mask;
216 set_fs(fs);
217 return result;
218 }
219
220 /*
221 * For now we lock out other simulaneous nfs calls for the same filesytem
222 * because we are single-threaded and don't want to get mismatched
223 * RPC replies.
224 */
225
226 int nfs_rpc_call(struct nfs_server *server, int *start, int *end)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
227 {
228 int result;
229
230 while (server->lock)
231 sleep_on(&server->wait);
232 server->lock = 1;
233 result = do_nfs_rpc_call(server, start, end);
234 server->lock = 0;
235 wake_up(&server->wait);
236 return result;
237 }
238