Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.33-rc2 345 lines 7.7 kB view raw
1/* 2 * smbiod.c 3 * 4 * Copyright (C) 2000, Charles Loep / Corel Corp. 5 * Copyright (C) 2001, Urban Widmark 6 */ 7 8 9#include <linux/sched.h> 10#include <linux/kernel.h> 11#include <linux/mm.h> 12#include <linux/string.h> 13#include <linux/stat.h> 14#include <linux/errno.h> 15#include <linux/slab.h> 16#include <linux/init.h> 17#include <linux/file.h> 18#include <linux/dcache.h> 19#include <linux/module.h> 20#include <linux/net.h> 21#include <linux/kthread.h> 22#include <net/ip.h> 23 24#include <linux/smb_fs.h> 25#include <linux/smbno.h> 26#include <linux/smb_mount.h> 27 28#include <asm/system.h> 29#include <asm/uaccess.h> 30 31#include "smb_debug.h" 32#include "request.h" 33#include "proto.h" 34 35enum smbiod_state { 36 SMBIOD_DEAD, 37 SMBIOD_STARTING, 38 SMBIOD_RUNNING, 39}; 40 41static enum smbiod_state smbiod_state = SMBIOD_DEAD; 42static struct task_struct *smbiod_thread; 43static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait); 44static LIST_HEAD(smb_servers); 45static DEFINE_SPINLOCK(servers_lock); 46 47#define SMBIOD_DATA_READY (1<<0) 48static unsigned long smbiod_flags; 49 50static int smbiod(void *); 51static int smbiod_start(void); 52 53/* 54 * called when there's work for us to do 55 */ 56void smbiod_wake_up(void) 57{ 58 if (smbiod_state == SMBIOD_DEAD) 59 return; 60 set_bit(SMBIOD_DATA_READY, &smbiod_flags); 61 wake_up_interruptible(&smbiod_wait); 62} 63 64/* 65 * start smbiod if none is running 66 */ 67static int smbiod_start(void) 68{ 69 struct task_struct *tsk; 70 int err = 0; 71 72 if (smbiod_state != SMBIOD_DEAD) 73 return 0; 74 smbiod_state = SMBIOD_STARTING; 75 __module_get(THIS_MODULE); 76 spin_unlock(&servers_lock); 77 tsk = kthread_run(smbiod, NULL, "smbiod"); 78 if (IS_ERR(tsk)) { 79 err = PTR_ERR(tsk); 80 module_put(THIS_MODULE); 81 } 82 83 spin_lock(&servers_lock); 84 if (err < 0) { 85 smbiod_state = SMBIOD_DEAD; 86 smbiod_thread = NULL; 87 } else { 88 smbiod_state = SMBIOD_RUNNING; 89 smbiod_thread = tsk; 90 } 91 return err; 92} 93 94/* 95 * register a server & start smbiod if necessary 96 */ 97int smbiod_register_server(struct smb_sb_info *server) 98{ 99 int ret; 100 spin_lock(&servers_lock); 101 list_add(&server->entry, &smb_servers); 102 VERBOSE("%p\n", server); 103 ret = smbiod_start(); 104 spin_unlock(&servers_lock); 105 return ret; 106} 107 108/* 109 * Unregister a server 110 * Must be called with the server lock held. 111 */ 112void smbiod_unregister_server(struct smb_sb_info *server) 113{ 114 spin_lock(&servers_lock); 115 list_del_init(&server->entry); 116 VERBOSE("%p\n", server); 117 spin_unlock(&servers_lock); 118 119 smbiod_wake_up(); 120 smbiod_flush(server); 121} 122 123void smbiod_flush(struct smb_sb_info *server) 124{ 125 struct list_head *tmp, *n; 126 struct smb_request *req; 127 128 list_for_each_safe(tmp, n, &server->xmitq) { 129 req = list_entry(tmp, struct smb_request, rq_queue); 130 req->rq_errno = -EIO; 131 list_del_init(&req->rq_queue); 132 smb_rput(req); 133 wake_up_interruptible(&req->rq_wait); 134 } 135 list_for_each_safe(tmp, n, &server->recvq) { 136 req = list_entry(tmp, struct smb_request, rq_queue); 137 req->rq_errno = -EIO; 138 list_del_init(&req->rq_queue); 139 smb_rput(req); 140 wake_up_interruptible(&req->rq_wait); 141 } 142} 143 144/* 145 * Wake up smbmount and make it reconnect to the server. 146 * This must be called with the server locked. 147 * 148 * FIXME: add smbconnect version to this 149 */ 150int smbiod_retry(struct smb_sb_info *server) 151{ 152 struct list_head *head; 153 struct smb_request *req; 154 struct pid *pid = get_pid(server->conn_pid); 155 int result = 0; 156 157 VERBOSE("state: %d\n", server->state); 158 if (server->state == CONN_VALID || server->state == CONN_RETRYING) 159 goto out; 160 161 smb_invalidate_inodes(server); 162 163 /* 164 * Some requests are meaningless after a retry, so we abort them. 165 * One example are all requests using 'fileid' since the files are 166 * closed on retry. 167 */ 168 head = server->xmitq.next; 169 while (head != &server->xmitq) { 170 req = list_entry(head, struct smb_request, rq_queue); 171 head = head->next; 172 173 req->rq_bytes_sent = 0; 174 if (req->rq_flags & SMB_REQ_NORETRY) { 175 VERBOSE("aborting request %p on xmitq\n", req); 176 req->rq_errno = -EIO; 177 list_del_init(&req->rq_queue); 178 smb_rput(req); 179 wake_up_interruptible(&req->rq_wait); 180 } 181 } 182 183 /* 184 * FIXME: test the code for retrying request we already sent 185 */ 186 head = server->recvq.next; 187 while (head != &server->recvq) { 188 req = list_entry(head, struct smb_request, rq_queue); 189 head = head->next; 190#if 0 191 if (req->rq_flags & SMB_REQ_RETRY) { 192 /* must move the request to the xmitq */ 193 VERBOSE("retrying request %p on recvq\n", req); 194 list_move(&req->rq_queue, &server->xmitq); 195 continue; 196 } 197#endif 198 199 VERBOSE("aborting request %p on recvq\n", req); 200 /* req->rq_rcls = ???; */ /* FIXME: set smb error code too? */ 201 req->rq_errno = -EIO; 202 list_del_init(&req->rq_queue); 203 smb_rput(req); 204 wake_up_interruptible(&req->rq_wait); 205 } 206 207 smb_close_socket(server); 208 209 if (!pid) { 210 /* FIXME: this is fatal, umount? */ 211 printk(KERN_ERR "smb_retry: no connection process\n"); 212 server->state = CONN_RETRIED; 213 goto out; 214 } 215 216 /* 217 * Change state so that only one retry per server will be started. 218 */ 219 server->state = CONN_RETRYING; 220 221 /* 222 * Note: use the "priv" flag, as a user process may need to reconnect. 223 */ 224 result = kill_pid(pid, SIGUSR1, 1); 225 if (result) { 226 /* FIXME: this is most likely fatal, umount? */ 227 printk(KERN_ERR "smb_retry: signal failed [%d]\n", result); 228 goto out; 229 } 230 VERBOSE("signalled pid %d\n", pid_nr(pid)); 231 232 /* FIXME: The retried requests should perhaps get a "time boost". */ 233 234out: 235 put_pid(pid); 236 return result; 237} 238 239/* 240 * Currently handles lockingX packets. 241 */ 242static void smbiod_handle_request(struct smb_sb_info *server) 243{ 244 PARANOIA("smbiod got a request ... and we don't implement oplocks!\n"); 245 server->rstate = SMB_RECV_DROP; 246} 247 248/* 249 * Do some IO for one server. 250 */ 251static void smbiod_doio(struct smb_sb_info *server) 252{ 253 int result; 254 int maxwork = 7; 255 256 if (server->state != CONN_VALID) 257 goto out; 258 259 do { 260 result = smb_request_recv(server); 261 if (result < 0) { 262 server->state = CONN_INVALID; 263 smbiod_retry(server); 264 goto out; /* reconnecting is slow */ 265 } else if (server->rstate == SMB_RECV_REQUEST) 266 smbiod_handle_request(server); 267 } while (result > 0 && maxwork-- > 0); 268 269 /* 270 * If there is more to read then we want to be sure to wake up again. 271 */ 272 if (server->state != CONN_VALID) 273 goto out; 274 if (smb_recv_available(server) > 0) 275 set_bit(SMBIOD_DATA_READY, &smbiod_flags); 276 277 do { 278 result = smb_request_send_server(server); 279 if (result < 0) { 280 server->state = CONN_INVALID; 281 smbiod_retry(server); 282 goto out; /* reconnecting is slow */ 283 } 284 } while (result > 0); 285 286 /* 287 * If the last request was not sent out we want to wake up again. 288 */ 289 if (!list_empty(&server->xmitq)) 290 set_bit(SMBIOD_DATA_READY, &smbiod_flags); 291 292out: 293 return; 294} 295 296/* 297 * smbiod kernel thread 298 */ 299static int smbiod(void *unused) 300{ 301 VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid); 302 303 for (;;) { 304 struct smb_sb_info *server; 305 struct list_head *pos, *n; 306 307 /* FIXME: Use poll? */ 308 wait_event_interruptible(smbiod_wait, 309 test_bit(SMBIOD_DATA_READY, &smbiod_flags)); 310 if (signal_pending(current)) { 311 spin_lock(&servers_lock); 312 smbiod_state = SMBIOD_DEAD; 313 spin_unlock(&servers_lock); 314 break; 315 } 316 317 clear_bit(SMBIOD_DATA_READY, &smbiod_flags); 318 319 spin_lock(&servers_lock); 320 if (list_empty(&smb_servers)) { 321 smbiod_state = SMBIOD_DEAD; 322 spin_unlock(&servers_lock); 323 break; 324 } 325 326 list_for_each_safe(pos, n, &smb_servers) { 327 server = list_entry(pos, struct smb_sb_info, entry); 328 VERBOSE("checking server %p\n", server); 329 330 if (server->state == CONN_VALID) { 331 spin_unlock(&servers_lock); 332 333 smb_lock_server(server); 334 smbiod_doio(server); 335 smb_unlock_server(server); 336 337 spin_lock(&servers_lock); 338 } 339 } 340 spin_unlock(&servers_lock); 341 } 342 343 VERBOSE("SMB Kernel thread exiting (%d) ...\n", current->pid); 344 module_put_and_exit(0); 345}