fs: cache optimise dentry and inode for rcu-walk
[deliverable/linux.git] / fs / ncpfs / inode.c
... / ...
CommitLineData
1/*
2 * inode.c
3 *
4 * Copyright (C) 1995, 1996 by Volker Lendecke
5 * Modified for big endian by J.F. Chadima and David S. Miller
6 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7 * Modified 1998 Wolfram Pienkoss for NLS
8 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
9 *
10 */
11
12#include <linux/module.h>
13
14#include <asm/system.h>
15#include <asm/uaccess.h>
16#include <asm/byteorder.h>
17
18#include <linux/time.h>
19#include <linux/kernel.h>
20#include <linux/mm.h>
21#include <linux/string.h>
22#include <linux/stat.h>
23#include <linux/errno.h>
24#include <linux/file.h>
25#include <linux/fcntl.h>
26#include <linux/slab.h>
27#include <linux/vmalloc.h>
28#include <linux/init.h>
29#include <linux/vfs.h>
30#include <linux/mount.h>
31#include <linux/seq_file.h>
32
33#include <linux/ncp_fs.h>
34
35#include <net/sock.h>
36
37#include "ncplib_kernel.h"
38#include "getopt.h"
39
40#define NCP_DEFAULT_FILE_MODE 0600
41#define NCP_DEFAULT_DIR_MODE 0700
42#define NCP_DEFAULT_TIME_OUT 10
43#define NCP_DEFAULT_RETRY_COUNT 20
44
45static void ncp_evict_inode(struct inode *);
46static void ncp_put_super(struct super_block *);
47static int ncp_statfs(struct dentry *, struct kstatfs *);
48static int ncp_show_options(struct seq_file *, struct vfsmount *);
49
50static struct kmem_cache * ncp_inode_cachep;
51
52static struct inode *ncp_alloc_inode(struct super_block *sb)
53{
54 struct ncp_inode_info *ei;
55 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
56 if (!ei)
57 return NULL;
58 return &ei->vfs_inode;
59}
60
61static void ncp_i_callback(struct rcu_head *head)
62{
63 struct inode *inode = container_of(head, struct inode, i_rcu);
64 INIT_LIST_HEAD(&inode->i_dentry);
65 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
66}
67
68static void ncp_destroy_inode(struct inode *inode)
69{
70 call_rcu(&inode->i_rcu, ncp_i_callback);
71}
72
73static void init_once(void *foo)
74{
75 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
76
77 mutex_init(&ei->open_mutex);
78 inode_init_once(&ei->vfs_inode);
79}
80
81static int init_inodecache(void)
82{
83 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
84 sizeof(struct ncp_inode_info),
85 0, (SLAB_RECLAIM_ACCOUNT|
86 SLAB_MEM_SPREAD),
87 init_once);
88 if (ncp_inode_cachep == NULL)
89 return -ENOMEM;
90 return 0;
91}
92
93static void destroy_inodecache(void)
94{
95 kmem_cache_destroy(ncp_inode_cachep);
96}
97
98static int ncp_remount(struct super_block *sb, int *flags, char* data)
99{
100 *flags |= MS_NODIRATIME;
101 return 0;
102}
103
104static const struct super_operations ncp_sops =
105{
106 .alloc_inode = ncp_alloc_inode,
107 .destroy_inode = ncp_destroy_inode,
108 .drop_inode = generic_delete_inode,
109 .evict_inode = ncp_evict_inode,
110 .put_super = ncp_put_super,
111 .statfs = ncp_statfs,
112 .remount_fs = ncp_remount,
113 .show_options = ncp_show_options,
114};
115
116/*
117 * Fill in the ncpfs-specific information in the inode.
118 */
119static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
120{
121 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
122 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
123 NCP_FINFO(inode)->volNumber = nwinfo->volume;
124}
125
126void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
127{
128 ncp_update_dirent(inode, nwinfo);
129 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
130 NCP_FINFO(inode)->access = nwinfo->access;
131 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
132 sizeof(nwinfo->file_handle));
133 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
134 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
135 NCP_FINFO(inode)->dirEntNum);
136}
137
138static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
139{
140 /* NFS namespace mode overrides others if it's set. */
141 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
142 nwi->entryName, nwi->nfs.mode);
143 if (nwi->nfs.mode) {
144 /* XXX Security? */
145 inode->i_mode = nwi->nfs.mode;
146 }
147
148 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
149
150 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
151 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
152 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
153 inode->i_atime.tv_nsec = 0;
154 inode->i_mtime.tv_nsec = 0;
155 inode->i_ctime.tv_nsec = 0;
156}
157
158static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
159{
160 struct nw_info_struct *nwi = &nwinfo->i;
161 struct ncp_server *server = NCP_SERVER(inode);
162
163 if (nwi->attributes & aDIR) {
164 inode->i_mode = server->m.dir_mode;
165 /* for directories dataStreamSize seems to be some
166 Object ID ??? */
167 i_size_write(inode, NCP_BLOCK_SIZE);
168 } else {
169 u32 size;
170
171 inode->i_mode = server->m.file_mode;
172 size = le32_to_cpu(nwi->dataStreamSize);
173 i_size_write(inode, size);
174#ifdef CONFIG_NCPFS_EXTRAS
175 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
176 && (nwi->attributes & aSHARED)) {
177 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
178 case aHIDDEN:
179 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
180 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
181 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
182 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
183 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
184 break;
185 }
186 }
187 /* FALLTHROUGH */
188 case 0:
189 if (server->m.flags & NCP_MOUNT_EXTRAS)
190 inode->i_mode |= S_IRUGO;
191 break;
192 case aSYSTEM:
193 if (server->m.flags & NCP_MOUNT_EXTRAS)
194 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
195 break;
196 /* case aSYSTEM|aHIDDEN: */
197 default:
198 /* reserved combination */
199 break;
200 }
201 }
202#endif
203 }
204 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
205}
206
207void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
208{
209 NCP_FINFO(inode)->flags = 0;
210 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
211 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
212 ncp_update_attrs(inode, nwinfo);
213 }
214
215 ncp_update_dates(inode, &nwinfo->i);
216 ncp_update_dirent(inode, nwinfo);
217}
218
219/*
220 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
221 */
222static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
223{
224 struct ncp_server *server = NCP_SERVER(inode);
225
226 NCP_FINFO(inode)->flags = 0;
227
228 ncp_update_attrs(inode, nwinfo);
229
230 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
231
232 inode->i_nlink = 1;
233 inode->i_uid = server->m.uid;
234 inode->i_gid = server->m.gid;
235
236 ncp_update_dates(inode, &nwinfo->i);
237 ncp_update_inode(inode, nwinfo);
238}
239
240#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
241static const struct inode_operations ncp_symlink_inode_operations = {
242 .readlink = generic_readlink,
243 .follow_link = page_follow_link_light,
244 .put_link = page_put_link,
245 .setattr = ncp_notify_change,
246};
247#endif
248
249/*
250 * Get a new inode.
251 */
252struct inode *
253ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
254{
255 struct inode *inode;
256
257 if (info == NULL) {
258 printk(KERN_ERR "ncp_iget: info is NULL\n");
259 return NULL;
260 }
261
262 inode = new_inode(sb);
263 if (inode) {
264 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
265
266 inode->i_mapping->backing_dev_info = sb->s_bdi;
267 inode->i_ino = info->ino;
268 ncp_set_attr(inode, info);
269 if (S_ISREG(inode->i_mode)) {
270 inode->i_op = &ncp_file_inode_operations;
271 inode->i_fop = &ncp_file_operations;
272 } else if (S_ISDIR(inode->i_mode)) {
273 inode->i_op = &ncp_dir_inode_operations;
274 inode->i_fop = &ncp_dir_operations;
275#ifdef CONFIG_NCPFS_NFS_NS
276 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
277 init_special_inode(inode, inode->i_mode,
278 new_decode_dev(info->i.nfs.rdev));
279#endif
280#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
281 } else if (S_ISLNK(inode->i_mode)) {
282 inode->i_op = &ncp_symlink_inode_operations;
283 inode->i_data.a_ops = &ncp_symlink_aops;
284#endif
285 } else {
286 make_bad_inode(inode);
287 }
288 insert_inode_hash(inode);
289 } else
290 printk(KERN_ERR "ncp_iget: iget failed!\n");
291 return inode;
292}
293
294static void
295ncp_evict_inode(struct inode *inode)
296{
297 truncate_inode_pages(&inode->i_data, 0);
298 end_writeback(inode);
299
300 if (S_ISDIR(inode->i_mode)) {
301 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
302 }
303
304 if (ncp_make_closed(inode) != 0) {
305 /* We can't do anything but complain. */
306 printk(KERN_ERR "ncp_evict_inode: could not close\n");
307 }
308}
309
310static void ncp_stop_tasks(struct ncp_server *server) {
311 struct sock* sk = server->ncp_sock->sk;
312
313 lock_sock(sk);
314 sk->sk_error_report = server->error_report;
315 sk->sk_data_ready = server->data_ready;
316 sk->sk_write_space = server->write_space;
317 release_sock(sk);
318 del_timer_sync(&server->timeout_tm);
319 flush_scheduled_work();
320}
321
322static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
323{
324 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
325 unsigned int tmp;
326
327 if (server->m.uid != 0)
328 seq_printf(seq, ",uid=%u", server->m.uid);
329 if (server->m.gid != 0)
330 seq_printf(seq, ",gid=%u", server->m.gid);
331 if (server->m.mounted_uid != 0)
332 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
333 tmp = server->m.file_mode & S_IALLUGO;
334 if (tmp != NCP_DEFAULT_FILE_MODE)
335 seq_printf(seq, ",mode=0%o", tmp);
336 tmp = server->m.dir_mode & S_IALLUGO;
337 if (tmp != NCP_DEFAULT_DIR_MODE)
338 seq_printf(seq, ",dirmode=0%o", tmp);
339 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
340 tmp = server->m.time_out * 100 / HZ;
341 seq_printf(seq, ",timeout=%u", tmp);
342 }
343 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
344 seq_printf(seq, ",retry=%u", server->m.retry_count);
345 if (server->m.flags != 0)
346 seq_printf(seq, ",flags=%lu", server->m.flags);
347 if (server->m.wdog_pid != NULL)
348 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
349
350 return 0;
351}
352
353static const struct ncp_option ncp_opts[] = {
354 { "uid", OPT_INT, 'u' },
355 { "gid", OPT_INT, 'g' },
356 { "owner", OPT_INT, 'o' },
357 { "mode", OPT_INT, 'm' },
358 { "dirmode", OPT_INT, 'd' },
359 { "timeout", OPT_INT, 't' },
360 { "retry", OPT_INT, 'r' },
361 { "flags", OPT_INT, 'f' },
362 { "wdogpid", OPT_INT, 'w' },
363 { "ncpfd", OPT_INT, 'n' },
364 { "infofd", OPT_INT, 'i' }, /* v5 */
365 { "version", OPT_INT, 'v' },
366 { NULL, 0, 0 } };
367
368static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
369 int optval;
370 char *optarg;
371 unsigned long optint;
372 int version = 0;
373 int ret;
374
375 data->flags = 0;
376 data->int_flags = 0;
377 data->mounted_uid = 0;
378 data->wdog_pid = NULL;
379 data->ncp_fd = ~0;
380 data->time_out = NCP_DEFAULT_TIME_OUT;
381 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
382 data->uid = 0;
383 data->gid = 0;
384 data->file_mode = NCP_DEFAULT_FILE_MODE;
385 data->dir_mode = NCP_DEFAULT_DIR_MODE;
386 data->info_fd = -1;
387 data->mounted_vol[0] = 0;
388
389 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
390 ret = optval;
391 if (ret < 0)
392 goto err;
393 switch (optval) {
394 case 'u':
395 data->uid = optint;
396 break;
397 case 'g':
398 data->gid = optint;
399 break;
400 case 'o':
401 data->mounted_uid = optint;
402 break;
403 case 'm':
404 data->file_mode = optint;
405 break;
406 case 'd':
407 data->dir_mode = optint;
408 break;
409 case 't':
410 data->time_out = optint;
411 break;
412 case 'r':
413 data->retry_count = optint;
414 break;
415 case 'f':
416 data->flags = optint;
417 break;
418 case 'w':
419 data->wdog_pid = find_get_pid(optint);
420 break;
421 case 'n':
422 data->ncp_fd = optint;
423 break;
424 case 'i':
425 data->info_fd = optint;
426 break;
427 case 'v':
428 ret = -ECHRNG;
429 if (optint < NCP_MOUNT_VERSION_V4)
430 goto err;
431 if (optint > NCP_MOUNT_VERSION_V5)
432 goto err;
433 version = optint;
434 break;
435
436 }
437 }
438 return 0;
439err:
440 put_pid(data->wdog_pid);
441 data->wdog_pid = NULL;
442 return ret;
443}
444
445static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
446{
447 struct ncp_mount_data_kernel data;
448 struct ncp_server *server;
449 struct file *ncp_filp;
450 struct inode *root_inode;
451 struct inode *sock_inode;
452 struct socket *sock;
453 int error;
454 int default_bufsize;
455#ifdef CONFIG_NCPFS_PACKET_SIGNING
456 int options;
457#endif
458 struct ncp_entry_info finfo;
459
460 data.wdog_pid = NULL;
461 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
462 if (!server)
463 return -ENOMEM;
464 sb->s_fs_info = server;
465
466 error = -EFAULT;
467 if (raw_data == NULL)
468 goto out;
469 switch (*(int*)raw_data) {
470 case NCP_MOUNT_VERSION:
471 {
472 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
473
474 data.flags = md->flags;
475 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
476 data.mounted_uid = md->mounted_uid;
477 data.wdog_pid = find_get_pid(md->wdog_pid);
478 data.ncp_fd = md->ncp_fd;
479 data.time_out = md->time_out;
480 data.retry_count = md->retry_count;
481 data.uid = md->uid;
482 data.gid = md->gid;
483 data.file_mode = md->file_mode;
484 data.dir_mode = md->dir_mode;
485 data.info_fd = -1;
486 memcpy(data.mounted_vol, md->mounted_vol,
487 NCP_VOLNAME_LEN+1);
488 }
489 break;
490 case NCP_MOUNT_VERSION_V4:
491 {
492 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
493
494 data.flags = md->flags;
495 data.int_flags = 0;
496 data.mounted_uid = md->mounted_uid;
497 data.wdog_pid = find_get_pid(md->wdog_pid);
498 data.ncp_fd = md->ncp_fd;
499 data.time_out = md->time_out;
500 data.retry_count = md->retry_count;
501 data.uid = md->uid;
502 data.gid = md->gid;
503 data.file_mode = md->file_mode;
504 data.dir_mode = md->dir_mode;
505 data.info_fd = -1;
506 data.mounted_vol[0] = 0;
507 }
508 break;
509 default:
510 error = -ECHRNG;
511 if (memcmp(raw_data, "vers", 4) == 0) {
512 error = ncp_parse_options(&data, raw_data);
513 }
514 if (error)
515 goto out;
516 break;
517 }
518 error = -EBADF;
519 ncp_filp = fget(data.ncp_fd);
520 if (!ncp_filp)
521 goto out;
522 error = -ENOTSOCK;
523 sock_inode = ncp_filp->f_path.dentry->d_inode;
524 if (!S_ISSOCK(sock_inode->i_mode))
525 goto out_fput;
526 sock = SOCKET_I(sock_inode);
527 if (!sock)
528 goto out_fput;
529
530 if (sock->type == SOCK_STREAM)
531 default_bufsize = 0xF000;
532 else
533 default_bufsize = 1024;
534
535 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
536 sb->s_maxbytes = 0xFFFFFFFFU;
537 sb->s_blocksize = 1024; /* Eh... Is this correct? */
538 sb->s_blocksize_bits = 10;
539 sb->s_magic = NCP_SUPER_MAGIC;
540 sb->s_op = &ncp_sops;
541 sb->s_bdi = &server->bdi;
542
543 server = NCP_SBP(sb);
544 memset(server, 0, sizeof(*server));
545
546 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
547 if (error)
548 goto out_bdi;
549
550 server->ncp_filp = ncp_filp;
551 server->ncp_sock = sock;
552
553 if (data.info_fd != -1) {
554 struct socket *info_sock;
555
556 error = -EBADF;
557 server->info_filp = fget(data.info_fd);
558 if (!server->info_filp)
559 goto out_fput;
560 error = -ENOTSOCK;
561 sock_inode = server->info_filp->f_path.dentry->d_inode;
562 if (!S_ISSOCK(sock_inode->i_mode))
563 goto out_fput2;
564 info_sock = SOCKET_I(sock_inode);
565 if (!info_sock)
566 goto out_fput2;
567 error = -EBADFD;
568 if (info_sock->type != SOCK_STREAM)
569 goto out_fput2;
570 server->info_sock = info_sock;
571 }
572
573/* server->lock = 0; */
574 mutex_init(&server->mutex);
575 server->packet = NULL;
576/* server->buffer_size = 0; */
577/* server->conn_status = 0; */
578/* server->root_dentry = NULL; */
579/* server->root_setuped = 0; */
580 mutex_init(&server->root_setup_lock);
581#ifdef CONFIG_NCPFS_PACKET_SIGNING
582/* server->sign_wanted = 0; */
583/* server->sign_active = 0; */
584#endif
585 init_rwsem(&server->auth_rwsem);
586 server->auth.auth_type = NCP_AUTH_NONE;
587/* server->auth.object_name_len = 0; */
588/* server->auth.object_name = NULL; */
589/* server->auth.object_type = 0; */
590/* server->priv.len = 0; */
591/* server->priv.data = NULL; */
592
593 server->m = data;
594 /* Althought anything producing this is buggy, it happens
595 now because of PATH_MAX changes.. */
596 if (server->m.time_out < 1) {
597 server->m.time_out = 10;
598 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
599 }
600 server->m.time_out = server->m.time_out * HZ / 100;
601 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
602 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
603
604#ifdef CONFIG_NCPFS_NLS
605 /* load the default NLS charsets */
606 server->nls_vol = load_nls_default();
607 server->nls_io = load_nls_default();
608#endif /* CONFIG_NCPFS_NLS */
609
610 atomic_set(&server->dentry_ttl, 0); /* no caching */
611
612 INIT_LIST_HEAD(&server->tx.requests);
613 mutex_init(&server->rcv.creq_mutex);
614 server->tx.creq = NULL;
615 server->rcv.creq = NULL;
616
617 init_timer(&server->timeout_tm);
618#undef NCP_PACKET_SIZE
619#define NCP_PACKET_SIZE 131072
620 error = -ENOMEM;
621 server->packet_size = NCP_PACKET_SIZE;
622 server->packet = vmalloc(NCP_PACKET_SIZE);
623 if (server->packet == NULL)
624 goto out_nls;
625 server->txbuf = vmalloc(NCP_PACKET_SIZE);
626 if (server->txbuf == NULL)
627 goto out_packet;
628 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
629 if (server->rxbuf == NULL)
630 goto out_txbuf;
631
632 lock_sock(sock->sk);
633 server->data_ready = sock->sk->sk_data_ready;
634 server->write_space = sock->sk->sk_write_space;
635 server->error_report = sock->sk->sk_error_report;
636 sock->sk->sk_user_data = server;
637 sock->sk->sk_data_ready = ncp_tcp_data_ready;
638 sock->sk->sk_error_report = ncp_tcp_error_report;
639 if (sock->type == SOCK_STREAM) {
640 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
641 server->rcv.len = 10;
642 server->rcv.state = 0;
643 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
644 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
645 sock->sk->sk_write_space = ncp_tcp_write_space;
646 } else {
647 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
648 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
649 server->timeout_tm.data = (unsigned long)server;
650 server->timeout_tm.function = ncpdgram_timeout_call;
651 }
652 release_sock(sock->sk);
653
654 ncp_lock_server(server);
655 error = ncp_connect(server);
656 ncp_unlock_server(server);
657 if (error < 0)
658 goto out_rxbuf;
659 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
660
661 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
662#ifdef CONFIG_NCPFS_PACKET_SIGNING
663 if (ncp_negotiate_size_and_options(server, default_bufsize,
664 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
665 {
666 if (options != NCP_DEFAULT_OPTIONS)
667 {
668 if (ncp_negotiate_size_and_options(server,
669 default_bufsize,
670 options & 2,
671 &(server->buffer_size), &options) != 0)
672
673 {
674 goto out_disconnect;
675 }
676 }
677 ncp_lock_server(server);
678 if (options & 2)
679 server->sign_wanted = 1;
680 ncp_unlock_server(server);
681 }
682 else
683#endif /* CONFIG_NCPFS_PACKET_SIGNING */
684 if (ncp_negotiate_buffersize(server, default_bufsize,
685 &(server->buffer_size)) != 0)
686 goto out_disconnect;
687 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
688
689 memset(&finfo, 0, sizeof(finfo));
690 finfo.i.attributes = aDIR;
691 finfo.i.dataStreamSize = 0; /* ignored */
692 finfo.i.dirEntNum = 0;
693 finfo.i.DosDirNum = 0;
694#ifdef CONFIG_NCPFS_SMALLDOS
695 finfo.i.NSCreator = NW_NS_DOS;
696#endif
697 finfo.volume = NCP_NUMBER_OF_VOLUMES;
698 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
699 finfo.i.creationTime = finfo.i.modifyTime
700 = cpu_to_le16(0x0000);
701 finfo.i.creationDate = finfo.i.modifyDate
702 = finfo.i.lastAccessDate
703 = cpu_to_le16(0x0C21);
704 finfo.i.nameLen = 0;
705 finfo.i.entryName[0] = '\0';
706
707 finfo.opened = 0;
708 finfo.ino = 2; /* tradition */
709
710 server->name_space[finfo.volume] = NW_NS_DOS;
711
712 error = -ENOMEM;
713 root_inode = ncp_iget(sb, &finfo);
714 if (!root_inode)
715 goto out_disconnect;
716 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
717 sb->s_root = d_alloc_root(root_inode);
718 if (!sb->s_root)
719 goto out_no_root;
720 d_set_d_op(sb->s_root, &ncp_root_dentry_operations);
721 return 0;
722
723out_no_root:
724 iput(root_inode);
725out_disconnect:
726 ncp_lock_server(server);
727 ncp_disconnect(server);
728 ncp_unlock_server(server);
729out_rxbuf:
730 ncp_stop_tasks(server);
731 vfree(server->rxbuf);
732out_txbuf:
733 vfree(server->txbuf);
734out_packet:
735 vfree(server->packet);
736out_nls:
737#ifdef CONFIG_NCPFS_NLS
738 unload_nls(server->nls_io);
739 unload_nls(server->nls_vol);
740#endif
741 mutex_destroy(&server->rcv.creq_mutex);
742 mutex_destroy(&server->root_setup_lock);
743 mutex_destroy(&server->mutex);
744out_fput2:
745 if (server->info_filp)
746 fput(server->info_filp);
747out_fput:
748 bdi_destroy(&server->bdi);
749out_bdi:
750 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
751 *
752 * The previously used put_filp(ncp_filp); was bogus, since
753 * it doesn't perform proper unlocking.
754 */
755 fput(ncp_filp);
756out:
757 put_pid(data.wdog_pid);
758 sb->s_fs_info = NULL;
759 kfree(server);
760 return error;
761}
762
763static void ncp_put_super(struct super_block *sb)
764{
765 struct ncp_server *server = NCP_SBP(sb);
766
767 ncp_lock_server(server);
768 ncp_disconnect(server);
769 ncp_unlock_server(server);
770
771 ncp_stop_tasks(server);
772
773#ifdef CONFIG_NCPFS_NLS
774 /* unload the NLS charsets */
775 unload_nls(server->nls_vol);
776 unload_nls(server->nls_io);
777#endif /* CONFIG_NCPFS_NLS */
778 mutex_destroy(&server->rcv.creq_mutex);
779 mutex_destroy(&server->root_setup_lock);
780 mutex_destroy(&server->mutex);
781
782 if (server->info_filp)
783 fput(server->info_filp);
784 fput(server->ncp_filp);
785 kill_pid(server->m.wdog_pid, SIGTERM, 1);
786 put_pid(server->m.wdog_pid);
787
788 bdi_destroy(&server->bdi);
789 kfree(server->priv.data);
790 kfree(server->auth.object_name);
791 vfree(server->rxbuf);
792 vfree(server->txbuf);
793 vfree(server->packet);
794 sb->s_fs_info = NULL;
795 kfree(server);
796}
797
798static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
799{
800 struct dentry* d;
801 struct inode* i;
802 struct ncp_inode_info* ni;
803 struct ncp_server* s;
804 struct ncp_volume_info vi;
805 struct super_block *sb = dentry->d_sb;
806 int err;
807 __u8 dh;
808
809 d = sb->s_root;
810 if (!d) {
811 goto dflt;
812 }
813 i = d->d_inode;
814 if (!i) {
815 goto dflt;
816 }
817 ni = NCP_FINFO(i);
818 if (!ni) {
819 goto dflt;
820 }
821 s = NCP_SBP(sb);
822 if (!s) {
823 goto dflt;
824 }
825 if (!s->m.mounted_vol[0]) {
826 goto dflt;
827 }
828
829 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
830 if (err) {
831 goto dflt;
832 }
833 err = ncp_get_directory_info(s, dh, &vi);
834 ncp_dirhandle_free(s, dh);
835 if (err) {
836 goto dflt;
837 }
838 buf->f_type = NCP_SUPER_MAGIC;
839 buf->f_bsize = vi.sectors_per_block * 512;
840 buf->f_blocks = vi.total_blocks;
841 buf->f_bfree = vi.free_blocks;
842 buf->f_bavail = vi.free_blocks;
843 buf->f_files = vi.total_dir_entries;
844 buf->f_ffree = vi.available_dir_entries;
845 buf->f_namelen = 12;
846 return 0;
847
848 /* We cannot say how much disk space is left on a mounted
849 NetWare Server, because free space is distributed over
850 volumes, and the current user might have disk quotas. So
851 free space is not that simple to determine. Our decision
852 here is to err conservatively. */
853
854dflt:;
855 buf->f_type = NCP_SUPER_MAGIC;
856 buf->f_bsize = NCP_BLOCK_SIZE;
857 buf->f_blocks = 0;
858 buf->f_bfree = 0;
859 buf->f_bavail = 0;
860 buf->f_namelen = 12;
861 return 0;
862}
863
864int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
865{
866 struct inode *inode = dentry->d_inode;
867 int result = 0;
868 __le32 info_mask;
869 struct nw_modify_dos_info info;
870 struct ncp_server *server;
871
872 result = -EIO;
873
874 server = NCP_SERVER(inode);
875 if (!server) /* How this could happen? */
876 goto out;
877
878 /* ageing the dentry to force validation */
879 ncp_age_dentry(server, dentry);
880
881 result = inode_change_ok(inode, attr);
882 if (result < 0)
883 goto out;
884
885 result = -EPERM;
886 if (((attr->ia_valid & ATTR_UID) &&
887 (attr->ia_uid != server->m.uid)))
888 goto out;
889
890 if (((attr->ia_valid & ATTR_GID) &&
891 (attr->ia_gid != server->m.gid)))
892 goto out;
893
894 if (((attr->ia_valid & ATTR_MODE) &&
895 (attr->ia_mode &
896 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
897 goto out;
898
899 info_mask = 0;
900 memset(&info, 0, sizeof(info));
901
902#if 1
903 if ((attr->ia_valid & ATTR_MODE) != 0)
904 {
905 umode_t newmode = attr->ia_mode;
906
907 info_mask |= DM_ATTRIBUTES;
908
909 if (S_ISDIR(inode->i_mode)) {
910 newmode &= server->m.dir_mode;
911 } else {
912#ifdef CONFIG_NCPFS_EXTRAS
913 if (server->m.flags & NCP_MOUNT_EXTRAS) {
914 /* any non-default execute bit set */
915 if (newmode & ~server->m.file_mode & S_IXUGO)
916 info.attributes |= aSHARED | aSYSTEM;
917 /* read for group/world and not in default file_mode */
918 else if (newmode & ~server->m.file_mode & S_IRUGO)
919 info.attributes |= aSHARED;
920 } else
921#endif
922 newmode &= server->m.file_mode;
923 }
924 if (newmode & S_IWUGO)
925 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
926 else
927 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
928
929#ifdef CONFIG_NCPFS_NFS_NS
930 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
931 result = ncp_modify_nfs_info(server,
932 NCP_FINFO(inode)->volNumber,
933 NCP_FINFO(inode)->dirEntNum,
934 attr->ia_mode, 0);
935 if (result != 0)
936 goto out;
937 info.attributes &= ~(aSHARED | aSYSTEM);
938 {
939 /* mark partial success */
940 struct iattr tmpattr;
941
942 tmpattr.ia_valid = ATTR_MODE;
943 tmpattr.ia_mode = attr->ia_mode;
944
945 setattr_copy(inode, &tmpattr);
946 mark_inode_dirty(inode);
947 }
948 }
949#endif
950 }
951#endif
952
953 /* Do SIZE before attributes, otherwise mtime together with size does not work...
954 */
955 if ((attr->ia_valid & ATTR_SIZE) != 0) {
956 int written;
957
958 DPRINTK("ncpfs: trying to change size to %ld\n",
959 attr->ia_size);
960
961 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
962 result = -EACCES;
963 goto out;
964 }
965 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
966 attr->ia_size, 0, "", &written);
967
968 /* According to ndir, the changes only take effect after
969 closing the file */
970 ncp_inode_close(inode);
971 result = ncp_make_closed(inode);
972 if (result)
973 goto out;
974
975 if (attr->ia_size != i_size_read(inode)) {
976 result = vmtruncate(inode, attr->ia_size);
977 if (result)
978 goto out;
979 mark_inode_dirty(inode);
980 }
981 }
982 if ((attr->ia_valid & ATTR_CTIME) != 0) {
983 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
984 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
985 &info.creationTime, &info.creationDate);
986 }
987 if ((attr->ia_valid & ATTR_MTIME) != 0) {
988 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
989 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
990 &info.modifyTime, &info.modifyDate);
991 }
992 if ((attr->ia_valid & ATTR_ATIME) != 0) {
993 __le16 dummy;
994 info_mask |= (DM_LAST_ACCESS_DATE);
995 ncp_date_unix2dos(attr->ia_atime.tv_sec,
996 &dummy, &info.lastAccessDate);
997 }
998 if (info_mask != 0) {
999 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1000 inode, info_mask, &info);
1001 if (result != 0) {
1002 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1003 /* NetWare seems not to allow this. I
1004 do not know why. So, just tell the
1005 user everything went fine. This is
1006 a terrible hack, but I do not know
1007 how to do this correctly. */
1008 result = 0;
1009 } else
1010 goto out;
1011 }
1012#ifdef CONFIG_NCPFS_STRONG
1013 if ((!result) && (info_mask & DM_ATTRIBUTES))
1014 NCP_FINFO(inode)->nwattr = info.attributes;
1015#endif
1016 }
1017 if (result)
1018 goto out;
1019
1020 setattr_copy(inode, attr);
1021 mark_inode_dirty(inode);
1022
1023out:
1024 if (result > 0)
1025 result = -EACCES;
1026 return result;
1027}
1028
1029static struct dentry *ncp_mount(struct file_system_type *fs_type,
1030 int flags, const char *dev_name, void *data)
1031{
1032 return mount_nodev(fs_type, flags, data, ncp_fill_super);
1033}
1034
1035static struct file_system_type ncp_fs_type = {
1036 .owner = THIS_MODULE,
1037 .name = "ncpfs",
1038 .mount = ncp_mount,
1039 .kill_sb = kill_anon_super,
1040 .fs_flags = FS_BINARY_MOUNTDATA,
1041};
1042
1043static int __init init_ncp_fs(void)
1044{
1045 int err;
1046 DPRINTK("ncpfs: init_ncp_fs called\n");
1047
1048 err = init_inodecache();
1049 if (err)
1050 goto out1;
1051 err = register_filesystem(&ncp_fs_type);
1052 if (err)
1053 goto out;
1054 return 0;
1055out:
1056 destroy_inodecache();
1057out1:
1058 return err;
1059}
1060
1061static void __exit exit_ncp_fs(void)
1062{
1063 DPRINTK("ncpfs: exit_ncp_fs called\n");
1064 unregister_filesystem(&ncp_fs_type);
1065 destroy_inodecache();
1066}
1067
1068module_init(init_ncp_fs)
1069module_exit(exit_ncp_fs)
1070MODULE_LICENSE("GPL");
This page took 0.029264 seconds and 5 git commands to generate.