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 * Peter Eriksson - incorrect XID used to confuse Linux
15 * Florian La Roche - use the correct max size, if reading a packet and
16 * also verify, if the whole packet has been read...
17 * more checks should be done in proc.c...
18 *
19 */
20
21 #ifdef MODULE
22 #include <linux/module.h>
23 #endif
24
25 #include <linux/sched.h>
26 #include <linux/nfs_fs.h>
27 #include <linux/errno.h>
28 #include <linux/socket.h>
29 #include <linux/fcntl.h>
30 #include <asm/segment.h>
31 #include <linux/in.h>
32 #include <linux/net.h>
33 #include <linux/mm.h>
34
35 /* JEJB/JSP 2/7/94
36 * this must match the value of NFS_SLACK_SPACE in linux/fs/nfs/proc.c
37 * ***FIXME*** should probably put this in nfs_fs.h */
38 #define NFS_SLACK_SPACE 1024
39
40 #define _S(nr) (1<<((nr)-1))
41
42 /*
43 * We violate some modularity principles here by poking around
44 * in some socket internals. Besides having to call socket
45 * functions from kernel-space instead of user space, the socket
46 * interface does not lend itself well to being cleanly called
47 * without a file descriptor. Since the nfs calls can run on
48 * behalf of any process, the superblock maintains a file pointer
49 * to the server socket.
50 */
51
52 static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
/* ![[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)
*/
53 {
54 struct file *file;
55 struct inode *inode;
56 struct socket *sock;
57 unsigned short fs;
58 int result;
59 int xid;
60 int len;
61 select_table wait_table;
62 struct select_table_entry entry;
63 int (*select) (struct inode *, struct file *, int, select_table *);
64 int init_timeout, max_timeout;
65 int timeout;
66 int retrans;
67 int major_timeout_seen;
68 char *server_name;
69 int n;
70 int addrlen;
71 unsigned long old_mask;
72 /* JEJB/JSP 2/7/94
73 * This is for a 4 byte recv of the xid only */
74 int recv_xid;
75
76 xid = start[0];
77 len = ((char *) end) - ((char *) start);
78 file = server->file;
79 inode = file->f_inode;
80 select = file->f_op->select;
81 sock = &inode->u.socket_i;
82 if (!sock) {
83 printk("nfs_rpc_call: socki_lookup failed\n");
84 return -EBADF;
85 }
86 init_timeout = server->timeo;
87 max_timeout = NFS_MAX_RPC_TIMEOUT*HZ/10;
88 retrans = server->retrans;
89 major_timeout_seen = 0;
90 server_name = server->hostname;
91 old_mask = current->blocked;
92 current->blocked |= ~(_S(SIGKILL)
93 #if 0
94 | _S(SIGSTOP)
95 #endif
96 | ((server->flags & NFS_MOUNT_INTR)
97 ? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL
98 ? _S(SIGINT) : 0)
99 | (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL
100 ? _S(SIGQUIT) : 0))
101 : 0));
102 fs = get_fs();
103 set_fs(get_ds());
104 for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) {
105 /* JSP 1995-07-01 Use sendto() not send() to cope with multi-homed hosts
106 as we have set the socket to have INADDR_ANY as it's desination */
107 result = sock->ops->sendto(sock, (void *) start, len, 0, 0,
108 &(server->toaddr), sizeof((server->toaddr))) ;
109 if (result < 0) {
110 printk("nfs_rpc_call: send error = %d\n", result);
111 break;
112 }
113 re_select:
114 wait_table.nr = 0;
115 wait_table.entry = &entry;
116 current->state = TASK_INTERRUPTIBLE;
117 if (!select(inode, file, SEL_IN, &wait_table)
118 && !select(inode, file, SEL_IN, NULL)) {
119 if (timeout > max_timeout) {
120 /* JEJB/JSP 2/7/94
121 * This is useful to see if the system is
122 * hanging */
123 printk("NFS max timeout reached on %s\n",
124 server_name);
125 timeout = max_timeout;
126 }
127 current->timeout = jiffies + timeout;
128 schedule();
129 remove_wait_queue(entry.wait_address, &entry.wait);
130 current->state = TASK_RUNNING;
131 if (current->signal & ~current->blocked) {
132 current->timeout = 0;
133 result = -ERESTARTSYS;
134 break;
135 }
136 if (!current->timeout) {
137 if (n < retrans)
138 continue;
139 if (server->flags & NFS_MOUNT_SOFT) {
140 printk("NFS server %s not responding, "
141 "timed out\n", server_name);
142 result = -EIO;
143 break;
144 }
145 n = 0;
146 timeout = init_timeout;
147 init_timeout <<= 1;
148 if (!major_timeout_seen) {
149 printk("NFS server %s not responding, "
150 "still trying\n", server_name);
151 }
152 major_timeout_seen = 1;
153 continue;
154 }
155 else
156 current->timeout = 0;
157 }
158 else if (wait_table.nr)
159 remove_wait_queue(entry.wait_address, &entry.wait);
160 current->state = TASK_RUNNING;
161 addrlen = 0;
162 /* JEJB/JSP 2/7/94
163 * Get the xid from the next packet using a peek, so keep it
164 * on the recv queue. If it is wrong, it will be some reply
165 * we don't now need, so discard it */
166 result = sock->ops->recvfrom(sock, (void *)&recv_xid,
167 sizeof(recv_xid), 1, MSG_PEEK,
168 NULL, &addrlen);
169 if (result < 0) {
170 if (result == -EAGAIN) {
171 #if 0
172 printk("nfs_rpc_call: bad select ready\n");
173 #endif
174 goto re_select;
175 }
176 if (result == -ECONNREFUSED) {
177 #if 0
178 printk("nfs_rpc_call: server playing coy\n");
179 #endif
180 goto re_select;
181 }
182 if (result != -ERESTARTSYS) {
183 printk("nfs_rpc_call: recv error = %d\n",
184 -result);
185 }
186 break;
187 }
188 if (recv_xid == xid) {
189 if (major_timeout_seen)
190 printk("NFS server %s OK\n", server_name);
191 break;
192 }
193 /* JEJB/JSP 2/7/94
194 * we have xid mismatch, so discard the packet and start
195 * again. What a hack! but I can't call recvfrom with
196 * a null buffer yet. */
197 (void)sock->ops->recvfrom(sock, (void *)&recv_xid,
198 sizeof(recv_xid), 1, 0, NULL,
199 &addrlen);
200 #if 0
201 printk("nfs_rpc_call: XID mismatch\n");
202 #endif
203 goto re_select;
204 }
205 /* JEJB/JSP 2/7/94
206 *
207 * we have the correct xid, so read into the correct place and
208 * return it
209 *
210 */
211 result=sock->ops->recvfrom(sock, (void *)start,
212 size + 1024, 1, 0, NULL,
213 /* Here is NFS_SLACK_SPACE..., hack */
214 &addrlen);
215 if (result < 0) {
216 printk("NFS: notice message: result=%d\n", result);
217 } else if (result < addrlen) {
218 printk("NFS: just caught a too small read memory size..., email to NET channel\n");
219 printk("NFS: result=%d,addrlen=%d\n", result, addrlen);
220 result = -EIO;
221 }
222 current->blocked = old_mask;
223 set_fs(fs);
224 return result;
225 }
226
227 /*
228 * For now we lock out other simultaneous nfs calls for the same filesystem
229 * because we are single-threaded and don't want to get mismatched
230 * RPC replies.
231 */
232
233 int nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
/* ![[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)
*/
234 {
235 int result;
236
237 while (server->lock)
238 sleep_on(&server->wait);
239 server->lock = 1;
240 result = do_nfs_rpc_call(server, start, end, size);
241 server->lock = 0;
242 wake_up(&server->wait);
243 return result;
244 }
245