import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / smbfs / inode.c
1 /*
2  *  inode.c
3  *
4  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
5  *  Copyright (C) 1997 by Volker Lendecke
6  *
7  *  Please add a note about your changes to smbfs in the ChangeLog file.
8  */
9
10 #include <linux/config.h>
11 #include <linux/module.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/mm.h>
15 #include <linux/string.h>
16 #include <linux/stat.h>
17 #include <linux/errno.h>
18 #include <linux/locks.h>
19 #include <linux/slab.h>
20 #include <linux/init.h>
21 #include <linux/file.h>
22 #include <linux/dcache.h>
23 #include <linux/smp_lock.h>
24 #include <linux/nls.h>
25 #include <linux/seq_file.h>
26
27 #include <linux/smb_fs.h>
28 #include <linux/smbno.h>
29 #include <linux/smb_mount.h>
30
31 #include <asm/system.h>
32 #include <asm/uaccess.h>
33
34 #include "smb_debug.h"
35 #include "getopt.h"
36 #include "proto.h"
37
38 /* Always pick a default string */
39 #ifdef CONFIG_SMB_NLS_REMOTE
40 #define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE
41 #else
42 #define SMB_NLS_REMOTE ""
43 #endif
44
45 #define SMB_TTL_DEFAULT 1000
46 #define SMB_TIMEO_DEFAULT 30
47
48 static void smb_delete_inode(struct inode *);
49 static void smb_put_super(struct super_block *);
50 static int  smb_statfs(struct super_block *, struct statfs *);
51 static int  smb_show_options(struct seq_file *, struct vfsmount *);
52
53 static struct super_operations smb_sops =
54 {
55         put_inode:      force_delete,
56         delete_inode:   smb_delete_inode,
57         put_super:      smb_put_super,
58         statfs:         smb_statfs,
59         show_options:   smb_show_options,
60 };
61
62
63 /* We are always generating a new inode here */
64 struct inode *
65 smb_iget(struct super_block *sb, struct smb_fattr *fattr)
66 {
67         struct inode *result;
68
69         DEBUG1("smb_iget: %p\n", fattr);
70
71         result = new_inode(sb);
72         if (!result)
73                 return result;
74         result->i_ino = fattr->f_ino;
75         memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i));
76         smb_set_inode_attr(result, fattr);
77         if (S_ISREG(result->i_mode)) {
78                 result->i_op = &smb_file_inode_operations;
79                 result->i_fop = &smb_file_operations;
80                 result->i_data.a_ops = &smb_file_aops;
81         } else if (S_ISDIR(result->i_mode)) {
82                 struct smb_sb_info *server = &(sb->u.smbfs_sb);
83                 if (server->opt.capabilities & SMB_CAP_UNIX)
84                         result->i_op = &smb_dir_inode_operations_unix;
85                 else
86                         result->i_op = &smb_dir_inode_operations;
87                 result->i_fop = &smb_dir_operations;
88         } else if(S_ISLNK(result->i_mode)) {
89                 result->i_op = &smb_link_inode_operations;
90         } else {
91                 init_special_inode(result, result->i_mode, fattr->f_rdev);
92         }
93         insert_inode_hash(result);
94         return result;
95 }
96
97 /*
98  * Copy the inode data to a smb_fattr structure.
99  */
100 void
101 smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
102 {
103         memset(fattr, 0, sizeof(struct smb_fattr));
104         fattr->f_mode   = inode->i_mode;
105         fattr->f_nlink  = inode->i_nlink;
106         fattr->f_ino    = inode->i_ino;
107         fattr->f_uid    = inode->i_uid;
108         fattr->f_gid    = inode->i_gid;
109         fattr->f_rdev   = inode->i_rdev;
110         fattr->f_size   = inode->i_size;
111         fattr->f_mtime  = inode->i_mtime;
112         fattr->f_ctime  = inode->i_ctime;
113         fattr->f_atime  = inode->i_atime;
114         fattr->f_blksize= inode->i_blksize;
115         fattr->f_blocks = inode->i_blocks;
116
117         fattr->attr     = inode->u.smbfs_i.attr;
118         /*
119          * Keep the attributes in sync with the inode permissions.
120          */
121         if (fattr->f_mode & S_IWUSR)
122                 fattr->attr &= ~aRONLY;
123         else
124                 fattr->attr |= aRONLY;
125 }
126
127 /*
128  * Update the inode, possibly causing it to invalidate its pages if mtime/size
129  * is different from last time.
130  */
131 void
132 smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
133 {
134         /*
135          * A size change should have a different mtime, or same mtime
136          * but different size.
137          */
138         time_t last_time = inode->i_mtime;
139         loff_t last_sz = inode->i_size;
140
141         inode->i_mode   = fattr->f_mode;
142         inode->i_nlink  = fattr->f_nlink;
143         inode->i_uid    = fattr->f_uid;
144         inode->i_gid    = fattr->f_gid;
145         inode->i_rdev   = fattr->f_rdev;
146         inode->i_ctime  = fattr->f_ctime;
147         inode->i_blksize= fattr->f_blksize;
148         inode->i_blocks = fattr->f_blocks;
149         inode->i_size   = fattr->f_size;
150         inode->i_mtime  = fattr->f_mtime;
151         inode->i_atime  = fattr->f_atime;
152         inode->u.smbfs_i.attr = fattr->attr;
153         /*
154          * Update the "last time refreshed" field for revalidation.
155          */
156         inode->u.smbfs_i.oldmtime = jiffies;
157
158         if (inode->i_mtime != last_time || inode->i_size != last_sz) {
159                 VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
160                         inode->i_ino,
161                         (long) last_time, (long) inode->i_mtime,
162                         (long) last_sz, (long) inode->i_size);
163
164                 if (!S_ISDIR(inode->i_mode))
165                         invalidate_inode_pages(inode);
166         }
167 }
168
169 /*
170  * This is called if the connection has gone bad ...
171  * try to kill off all the current inodes.
172  */
173 void
174 smb_invalidate_inodes(struct smb_sb_info *server)
175 {
176         VERBOSE("\n");
177         shrink_dcache_sb(SB_of(server));
178         invalidate_inodes(SB_of(server));
179 }
180
181 /*
182  * This is called to update the inode attributes after
183  * we've made changes to a file or directory.
184  */
185 static int
186 smb_refresh_inode(struct dentry *dentry)
187 {
188         struct inode *inode = dentry->d_inode;
189         int error;
190         struct smb_fattr fattr;
191
192         error = smb_proc_getattr(dentry, &fattr);
193         if (!error) {
194                 smb_renew_times(dentry);
195                 /*
196                  * Check whether the type part of the mode changed,
197                  * and don't update the attributes if it did.
198                  *
199                  * And don't dick with the root inode
200                  */
201                 if (inode->i_ino == 2)
202                         return error;
203                 if (S_ISLNK(inode->i_mode))
204                         return error;   /* VFS will deal with it */
205
206                 if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
207                         smb_set_inode_attr(inode, &fattr);
208                 } else {
209                         /*
210                          * Big trouble! The inode has become a new object,
211                          * so any operations attempted on it are invalid.
212                          *
213                          * To limit damage, mark the inode as bad so that
214                          * subsequent lookup validations will fail.
215                          */
216                         PARANOIA("%s/%s changed mode, %07o to %07o\n",
217                                  DENTRY_PATH(dentry),
218                                  inode->i_mode, fattr.f_mode);
219
220                         fattr.f_mode = inode->i_mode; /* save mode */
221                         make_bad_inode(inode);
222                         inode->i_mode = fattr.f_mode; /* restore mode */
223                         /*
224                          * No need to worry about unhashing the dentry: the
225                          * lookup validation will see that the inode is bad.
226                          * But we do want to invalidate the caches ...
227                          */
228                         if (!S_ISDIR(inode->i_mode))
229                                 invalidate_inode_pages(inode);
230                         else
231                                 smb_invalid_dir_cache(inode);
232                         error = -EIO;
233                 }
234         }
235         return error;
236 }
237
238 /*
239  * This is called when we want to check whether the inode
240  * has changed on the server.  If it has changed, we must
241  * invalidate our local caches.
242  */
243 int
244 smb_revalidate_inode(struct dentry *dentry)
245 {
246         struct smb_sb_info *s = server_from_dentry(dentry);
247         struct inode *inode = dentry->d_inode;
248         int error = 0;
249
250         DEBUG1("smb_revalidate_inode\n");
251         lock_kernel();
252
253         /*
254          * Check whether we've recently refreshed the inode.
255          */
256         if (time_before(jiffies, inode->u.smbfs_i.oldmtime + SMB_MAX_AGE(s))) {
257                 VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n",
258                         inode->i_ino, jiffies, inode->u.smbfs_i.oldmtime);
259                 goto out;
260         }
261
262         error = smb_refresh_inode(dentry);
263 out:
264         unlock_kernel();
265         return error;
266 }
267
268 /*
269  * This routine is called when i_nlink == 0 and i_count goes to 0.
270  * All blocking cleanup operations need to go here to avoid races.
271  */
272 static void
273 smb_delete_inode(struct inode *ino)
274 {
275         DEBUG1("ino=%ld\n", ino->i_ino);
276         lock_kernel();
277         if (smb_close(ino))
278                 PARANOIA("could not close inode %ld\n", ino->i_ino);
279         unlock_kernel();
280         clear_inode(ino);
281 }
282
283 static struct option opts[] = {
284         { "version",    0, 'v' },
285         { "win95",      SMB_MOUNT_WIN95, 1 },
286         { "oldattr",    SMB_MOUNT_OLDATTR, 1 },
287         { "dirattr",    SMB_MOUNT_DIRATTR, 1 },
288         { "case",       SMB_MOUNT_CASE, 1 },
289         { "uid",        0, 'u' },
290         { "gid",        0, 'g' },
291         { "file_mode",  0, 'f' },
292         { "dir_mode",   0, 'd' },
293         { "iocharset",  0, 'i' },
294         { "codepage",   0, 'c' },
295         { "ttl",        0, 't' },
296         { "timeo",      0, 'o' },
297         { NULL,         0, 0}
298 };
299
300 static int
301 parse_options(struct smb_mount_data_kernel *mnt, char *options)
302 {
303         int c;
304         unsigned long flags;
305         unsigned long value;
306         char *optarg;
307         char *optopt;
308
309         flags = 0;
310         while ( (c = smb_getopt("smbfs", &options, opts,
311                                 &optopt, &optarg, &flags, &value)) > 0) {
312
313                 VERBOSE("'%s' -> '%s'\n", optopt, optarg ? optarg : "<none>");
314                 switch (c) {
315                 case 1:
316                         /* got a "flag" option */
317                         break;
318                 case 'v':
319                         if (value != SMB_MOUNT_VERSION) {
320                         printk ("smbfs: Bad mount version %ld, expected %d\n",
321                                 value, SMB_MOUNT_VERSION);
322                                 return 0;
323                         }
324                         mnt->version = value;
325                         break;
326                 case 'u':
327                         mnt->uid = value;
328                         flags |= SMB_MOUNT_UID;
329                         break;
330                 case 'g':
331                         mnt->gid = value;
332                         flags |= SMB_MOUNT_GID;
333                         break;
334                 case 'f':
335                         mnt->file_mode = (value & S_IRWXUGO) | S_IFREG;
336                         flags |= SMB_MOUNT_FMODE;
337                         break;
338                 case 'd':
339                         mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR;
340                         flags |= SMB_MOUNT_DMODE;
341                         break;
342                 case 'i':
343                         strncpy(mnt->codepage.local_name, optarg, 
344                                 SMB_NLS_MAXNAMELEN);
345                         break;
346                 case 'c':
347                         strncpy(mnt->codepage.remote_name, optarg,
348                                 SMB_NLS_MAXNAMELEN);
349                         break;
350                 case 't':
351                         mnt->ttl = value;
352                         break;
353                 case 'o':
354                         mnt->timeo = value;
355                         break;
356                 default:
357                         printk ("smbfs: Unrecognized mount option %s\n",
358                                 optopt);
359                         return -1;
360                 }
361         }
362         mnt->flags = flags;
363         return c;
364 }
365
366 /*
367  * smb_show_options() is for displaying mount options in /proc/mounts.
368  * It tries to avoid showing settings that were not changed from their
369  * defaults.
370  */
371 static int
372 smb_show_options(struct seq_file *s, struct vfsmount *m)
373 {
374         struct smb_mount_data_kernel *mnt = m->mnt_sb->u.smbfs_sb.mnt;
375         int i;
376
377         for (i = 0; opts[i].name != NULL; i++)
378                 if (mnt->flags & opts[i].flag)
379                         seq_printf(s, ",%s", opts[i].name);
380
381         if (mnt->flags & SMB_MOUNT_UID)
382                 seq_printf(s, ",uid=%d", mnt->uid);
383         if (mnt->flags & SMB_MOUNT_GID)
384                 seq_printf(s, ",gid=%d", mnt->gid);
385         if (mnt->mounted_uid != 0)
386                 seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid);
387
388         /* 
389          * Defaults for file_mode and dir_mode are unknown to us; they
390          * depend on the current umask of the user doing the mount.
391          */
392         if (mnt->flags & SMB_MOUNT_FMODE)
393                 seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO);
394         if (mnt->flags & SMB_MOUNT_DMODE)
395                 seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO);
396
397         if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT))
398                 seq_printf(s, ",iocharset=%s", mnt->codepage.local_name);
399         if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE))
400                 seq_printf(s, ",codepage=%s", mnt->codepage.remote_name);
401
402         if (mnt->ttl != SMB_TTL_DEFAULT)
403                 seq_printf(s, ",ttl=%d", mnt->ttl);
404         if (mnt->timeo != SMB_TIMEO_DEFAULT)
405                 seq_printf(s, ",timeo=%d", mnt->timeo);
406
407         return 0;
408 }
409
410 static void
411 smb_put_super(struct super_block *sb)
412 {
413         struct smb_sb_info *server = &(sb->u.smbfs_sb);
414
415         if (server->sock_file) {
416                 smb_dont_catch_keepalive(server);
417                 fput(server->sock_file);
418         }
419
420         if (server->conn_pid)
421                kill_proc(server->conn_pid, SIGTERM, 1);
422
423         smb_kfree(server->mnt);
424         smb_kfree(server->temp_buf);
425         if (server->packet)
426                 smb_vfree(server->packet);
427
428         if (server->remote_nls) {
429                 unload_nls(server->remote_nls);
430                 server->remote_nls = NULL;
431         }
432         if (server->local_nls) {
433                 unload_nls(server->local_nls);
434                 server->local_nls = NULL;
435         }
436 }
437
438 struct super_block *
439 smb_read_super(struct super_block *sb, void *raw_data, int silent)
440 {
441         struct smb_sb_info *server = &sb->u.smbfs_sb;
442         struct smb_mount_data_kernel *mnt;
443         struct smb_mount_data *oldmnt;
444         struct inode *root_inode;
445         struct smb_fattr root;
446         int ver;
447         void *mem;
448
449         if (!raw_data)
450                 goto out_no_data;
451
452         oldmnt = (struct smb_mount_data *) raw_data;
453         ver = oldmnt->version;
454         if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII)
455                 goto out_wrong_data;
456
457         sb->s_blocksize = 1024; /* Eh...  Is this correct? */
458         sb->s_blocksize_bits = 10;
459         sb->s_maxbytes = MAX_NON_LFS;
460         sb->s_magic = SMB_SUPER_MAGIC;
461         sb->s_op = &smb_sops;
462
463         server->mnt = NULL;
464         server->sock_file = NULL;
465         init_MUTEX(&server->sem);
466         init_waitqueue_head(&server->wait);
467         server->conn_pid = 0;
468         server->state = CONN_INVALID; /* no connection yet */
469         server->generation = 0;
470         server->packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE);
471         server->packet = smb_vmalloc(server->packet_size);
472         if (!server->packet)
473                 goto out_no_mem;
474
475         /* Allocate the global temp buffer */
476         server->temp_buf = smb_kmalloc(2*SMB_MAXPATHLEN+20, GFP_KERNEL);
477         if (!server->temp_buf)
478                 goto out_no_temp;
479
480         /* Setup NLS stuff */
481         server->remote_nls = NULL;
482         server->local_nls = NULL;
483         server->name_buf = server->temp_buf + SMB_MAXPATHLEN + 20;
484
485         /* Allocate the mount data structure */
486         /* FIXME: merge this with the other malloc and get a whole page? */
487         mem = smb_kmalloc(sizeof(struct smb_ops) +
488                           sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
489         if (!mem)
490                 goto out_no_mount;
491         server->mnt = mnt = mem;
492         server->ops = mem + sizeof(struct smb_mount_data_kernel);
493         smb_install_null_ops(server->ops);
494
495         memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
496         strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
497                 SMB_NLS_MAXNAMELEN);
498         strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
499                 SMB_NLS_MAXNAMELEN);
500
501         mnt->ttl = SMB_TTL_DEFAULT;
502         mnt->timeo = SMB_TIMEO_DEFAULT;
503         if (ver == SMB_MOUNT_OLDVERSION) {
504                 mnt->version = oldmnt->version;
505
506                 /* FIXME: is this enough to convert uid/gid's ? */
507                 mnt->uid = oldmnt->uid;
508                 mnt->gid = oldmnt->gid;
509
510                 mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG;
511                 mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR;
512
513                 mnt->flags = (oldmnt->file_mode >> 9) | SMB_MOUNT_UID |
514                         SMB_MOUNT_GID | SMB_MOUNT_FMODE | SMB_MOUNT_DMODE;
515         } else {
516                 mnt->file_mode = S_IRWXU | S_IRGRP | S_IXGRP |
517                                 S_IROTH | S_IXOTH | S_IFREG;
518                 mnt->dir_mode = S_IRWXU | S_IRGRP | S_IXGRP |
519                                 S_IROTH | S_IXOTH | S_IFDIR;
520                 if (parse_options(mnt, raw_data))
521                         goto out_bad_option;
522         }
523         smb_setcodepage(server, &mnt->codepage);
524         mnt->mounted_uid = current->uid;
525
526         /*
527          * Display the enabled options
528          * Note: smb_proc_getattr uses these in 2.4 (but was changed in 2.2)
529          */
530         if (mnt->flags & SMB_MOUNT_OLDATTR)
531                 printk("SMBFS: Using core getattr (Win 95 speedup)\n");
532         else if (mnt->flags & SMB_MOUNT_DIRATTR)
533                 printk("SMBFS: Using dir ff getattr\n");
534
535         /*
536          * Keep the super block locked while we get the root inode.
537          */
538         smb_init_root_dirent(server, &root);
539         root_inode = smb_iget(sb, &root);
540         if (!root_inode)
541                 goto out_no_root;
542
543         sb->s_root = d_alloc_root(root_inode);
544         if (!sb->s_root)
545                 goto out_no_root;
546
547         smb_new_dentry(sb->s_root);
548
549         return sb;
550
551 out_no_root:
552         iput(root_inode);
553 out_bad_option:
554         smb_kfree(server->mnt);
555 out_no_mount:
556         smb_kfree(server->temp_buf);
557 out_no_temp:
558         smb_vfree(server->packet);
559 out_no_mem:
560         if (!server->mnt)
561                 printk(KERN_ERR "smb_read_super: allocation failure\n");
562         goto out_fail;
563 out_wrong_data:
564         printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver);
565         goto out_fail;
566 out_no_data:
567         printk(KERN_ERR "smb_read_super: missing data argument\n");
568 out_fail:
569         return NULL;
570 }
571
572 static int
573 smb_statfs(struct super_block *sb, struct statfs *buf)
574 {
575         int result = smb_proc_dskattr(sb, buf);
576
577         buf->f_type = SMB_SUPER_MAGIC;
578         buf->f_namelen = SMB_MAXPATHLEN;
579         return result;
580 }
581
582 int
583 smb_notify_change(struct dentry *dentry, struct iattr *attr)
584 {
585         struct inode *inode = dentry->d_inode;
586         struct smb_sb_info *server = server_from_dentry(dentry);
587         unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO);
588         int error, changed, refresh = 0;
589         struct smb_fattr fattr;
590
591         error = smb_revalidate_inode(dentry);
592         if (error)
593                 goto out;
594
595         if ((error = inode_change_ok(inode, attr)) < 0)
596                 goto out;
597
598         error = -EPERM;
599         if ((attr->ia_valid & ATTR_UID) && (attr->ia_uid != server->mnt->uid))
600                 goto out;
601
602         if ((attr->ia_valid & ATTR_GID) && (attr->ia_uid != server->mnt->gid))
603                 goto out;
604
605         if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask))
606                 goto out;
607
608         if ((attr->ia_valid & ATTR_SIZE) != 0) {
609                 VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n",
610                         DENTRY_PATH(dentry),
611                         (long) inode->i_size, (long) attr->ia_size);
612
613                 filemap_fdatasync(inode->i_mapping);
614                 filemap_fdatawait(inode->i_mapping);
615
616                 error = smb_open(dentry, O_WRONLY);
617                 if (error)
618                         goto out;
619                 error = server->ops->truncate(inode, attr->ia_size);
620                 if (error)
621                         goto out;
622                 error = vmtruncate(inode, attr->ia_size);
623                 if (error)
624                         goto out;
625                 refresh = 1;
626         }
627
628         if (server->opt.capabilities & SMB_CAP_UNIX) {
629                 /* For now we don't want to set the size with setattr_unix */
630                 attr->ia_valid &= ~ATTR_SIZE;
631                 /* FIXME: only call if we actually want to set something? */
632                 error = smb_proc_setattr_unix(dentry, attr, 0, 0);
633                 if (!error)
634                         refresh = 1;
635                 goto out;
636         }
637
638         /*
639          * Initialize the fattr and check for changed fields.
640          * Note: CTIME under SMB is creation time rather than
641          * change time, so we don't attempt to change it.
642          */
643         smb_get_inode_attr(inode, &fattr);
644
645         changed = 0;
646         if ((attr->ia_valid & ATTR_MTIME) != 0) {
647                 fattr.f_mtime = attr->ia_mtime;
648                 changed = 1;
649         }
650         if ((attr->ia_valid & ATTR_ATIME) != 0) {
651                 fattr.f_atime = attr->ia_atime;
652                 /* Earlier protocols don't have an access time */
653                 if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
654                         changed = 1;
655         }
656         if (changed) {
657                 error = smb_proc_settime(dentry, &fattr);
658                 if (error)
659                         goto out;
660                 refresh = 1;
661         }
662
663         /*
664          * Check for mode changes ... we're extremely limited in
665          * what can be set for SMB servers: just the read-only bit.
666          */
667         if ((attr->ia_valid & ATTR_MODE) != 0) {
668                 VERBOSE("%s/%s mode change, old=%x, new=%x\n",
669                         DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode);
670                 changed = 0;
671                 if (attr->ia_mode & S_IWUSR) {
672                         if (fattr.attr & aRONLY) {
673                                 fattr.attr &= ~aRONLY;
674                                 changed = 1;
675                         }
676                 } else {
677                         if (!(fattr.attr & aRONLY)) {
678                                 fattr.attr |= aRONLY;
679                                 changed = 1;
680                         }
681                 }
682                 if (changed) {
683                         error = smb_proc_setattr(dentry, &fattr);
684                         if (error)
685                                 goto out;
686                         refresh = 1;
687                 }
688         }
689         error = 0;
690
691 out:
692         if (refresh)
693                 smb_refresh_inode(dentry);
694         return error;
695 }
696
697 #ifdef DEBUG_SMB_MALLOC
698 int smb_malloced;
699 int smb_current_kmalloced;
700 int smb_current_vmalloced;
701 #endif
702
703 static DECLARE_FSTYPE( smb_fs_type, "smbfs", smb_read_super, 0);
704
705 static int __init init_smb_fs(void)
706 {
707         DEBUG1("registering ...\n");
708
709 #ifdef DEBUG_SMB_MALLOC
710         smb_malloced = 0;
711         smb_current_kmalloced = 0;
712         smb_current_vmalloced = 0;
713 #endif
714
715         return register_filesystem(&smb_fs_type);
716 }
717
718 static void __exit exit_smb_fs(void)
719 {
720         DEBUG1("unregistering ...\n");
721         unregister_filesystem(&smb_fs_type);
722 #ifdef DEBUG_SMB_MALLOC
723         printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced);
724         printk(KERN_DEBUG "smb_current_kmalloced: %d\n",smb_current_kmalloced);
725         printk(KERN_DEBUG "smb_current_vmalloced: %d\n",smb_current_vmalloced);
726 #endif
727 }
728
729 EXPORT_NO_SYMBOLS;
730
731 module_init(init_smb_fs)
732 module_exit(exit_smb_fs)
733 MODULE_LICENSE("GPL");