]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/cifs/cifsfs.c
[CIFS] DFS support: provide shrinkable mounts
[karo-tx-linux.git] / fs / cifs / cifsfs.c
index ba8f7868cb23c84a5e713910f7b7d5a72bfc6f8a..e9f4ec7010926fb76e4808d3e4ed1bd0ab7f7cb5 100644 (file)
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
 #include <linux/mm.h>
+#include <linux/key-type.h>
+#include "dns_resolve.h"
+#include "cifs_spnego.h"
 #define CIFS_MAGIC_NUMBER 0xFF534D42   /* the first four bytes of SMB PDUs */
 
 #ifdef CONFIG_CIFS_QUOTA
 static struct quotactl_ops cifs_quotactl_ops;
 #endif /* QUOTA */
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-extern struct export_operations cifs_export_ops;
-#endif /* EXPERIMENTAL */
-
 int cifsFYI = 0;
 int cifsERROR = 1;
 int traceSMB = 0;
@@ -98,6 +97,9 @@ cifs_read_super(struct super_block *sb, void *data,
 {
        struct inode *inode;
        struct cifs_sb_info *cifs_sb;
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       int len;
+#endif
        int rc = 0;
 
        /* BB should we make this contingent on mount parm? */
@@ -107,6 +109,25 @@ cifs_read_super(struct super_block *sb, void *data,
        if (cifs_sb == NULL)
                return -ENOMEM;
 
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       /* copy mount params to sb for use in submounts */
+       /* BB: should we move this after the mount so we
+        * do not have to do the copy on failed mounts?
+        * BB: May be it is better to do simple copy before
+        * complex operation (mount), and in case of fail
+        * just exit instead of doing mount and attempting
+        * undo it if this copy fails?*/
+       len = strlen(data);
+       cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
+       if (cifs_sb->mountdata == NULL) {
+               kfree(sb->s_fs_info);
+               sb->s_fs_info = NULL;
+               return -ENOMEM;
+       }
+       strncpy(cifs_sb->mountdata, data, len + 1);
+       cifs_sb->mountdata[len] = '\0';
+#endif
+
        rc = cifs_mount(sb, cifs_sb, data, devname);
 
        if (rc) {
@@ -156,6 +177,12 @@ out_no_root:
 
 out_mount_failed:
        if (cifs_sb) {
+#ifdef CONFIG_CIFS_DFS_UPCALL
+               if (cifs_sb->mountdata) {
+                       kfree(cifs_sb->mountdata);
+                       cifs_sb->mountdata = NULL;
+               }
+#endif
                if (cifs_sb->local_nls)
                        unload_nls(cifs_sb->local_nls);
                kfree(cifs_sb);
@@ -179,6 +206,13 @@ cifs_put_super(struct super_block *sb)
        if (rc) {
                cERROR(1, ("cifs_umount failed with return code %d", rc));
        }
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       if (cifs_sb->mountdata) {
+               kfree(cifs_sb->mountdata);
+               cifs_sb->mountdata = NULL;
+       }
+#endif
+
        unload_nls(cifs_sb->local_nls);
        kfree(cifs_sb);
        return;
@@ -240,9 +274,9 @@ static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
 
        cifs_sb = CIFS_SB(inode->i_sb);
 
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
                return 0;
-       else /* file mode might have been restricted at mount time
+       else /* file mode might have been restricted at mount time
                on the client (above and beyond ACL on servers) for
                servers which do not support setting and viewing mode bits,
                so allowing client to check permissions is useful */
@@ -268,6 +302,7 @@ cifs_alloc_inode(struct super_block *sb)
        cifs_inode->cifsAttrs = 0x20;   /* default */
        atomic_set(&cifs_inode->inUse, 0);
        cifs_inode->time = 0;
+       cifs_inode->write_behind_rc = 0;
        /* Until the file is open and we have gotten oplock
        info back from the server, can not assume caching of
        file data or metadata */
@@ -312,15 +347,15 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
                                        seq_printf(s, ",domain=%s",
                                           cifs_sb->tcon->ses->domainName);
                        }
+                       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
+                          !(cifs_sb->tcon->unix_ext))
+                               seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
+                       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
+                          !(cifs_sb->tcon->unix_ext))
+                               seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
                }
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
                        seq_printf(s, ",posixpaths");
-               if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
-                  !(cifs_sb->tcon->unix_ext))
-                       seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
-               if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
-                  !(cifs_sb->tcon->unix_ext))
-                       seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
                seq_printf(s, ",rsize=%d", cifs_sb->rsize);
                seq_printf(s, ",wsize=%d", cifs_sb->wsize);
        }
@@ -346,7 +381,7 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
        if (pTcon) {
                cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
        } else {
-               return -EIO;
+               rc = -EIO;
        }
 
        FreeXid(xid);
@@ -436,6 +471,10 @@ static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *tcon;
 
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       dfs_shrink_umount_helper(vfsmnt);
+#endif /* CONFIG CIFS_DFS_UPCALL */
+
        if (!(flags & MNT_FORCE))
                return;
        cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
@@ -553,7 +592,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
        return remote_llseek(file, offset, origin);
 }
 
-static struct file_system_type cifs_fs_type = {
+struct file_system_type cifs_fs_type = {
        .owner = THIS_MODULE,
        .name = "cifs",
        .get_sb = cifs_get_sb,
@@ -716,7 +755,7 @@ static int
 cifs_init_inodecache(void)
 {
        cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
-                                             sizeof (struct cifsInodeInfo),
+                                             sizeof(struct cifsInodeInfo),
                                              0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
                                              cifs_init_once);
@@ -816,8 +855,8 @@ static int
 cifs_init_mids(void)
 {
        cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
-                               sizeof (struct mid_q_entry), 0,
-                               SLAB_HWCACHE_ALIGN, NULL);
+                                           sizeof(struct mid_q_entry), 0,
+                                           SLAB_HWCACHE_ALIGN, NULL);
        if (cifs_mid_cachep == NULL)
                return -ENOMEM;
 
@@ -829,8 +868,8 @@ cifs_init_mids(void)
        }
 
        cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs",
-                               sizeof (struct oplock_q_entry), 0,
-                               SLAB_HWCACHE_ALIGN, NULL);
+                                       sizeof(struct oplock_q_entry), 0,
+                                       SLAB_HWCACHE_ALIGN, NULL);
        if (cifs_oplock_cachep == NULL) {
                mempool_destroy(cifs_mid_poolp);
                kmem_cache_destroy(cifs_mid_cachep);
@@ -854,7 +893,7 @@ static int cifs_oplock_thread(void *dummyarg)
        struct cifsTconInfo *pTcon;
        struct inode *inode;
        __u16  netfid;
-       int rc;
+       int rc, waitrc = 0;
 
        set_freezable();
        do {
@@ -882,12 +921,15 @@ static int cifs_oplock_thread(void *dummyarg)
                                the call */
                                /* mutex_lock(&inode->i_mutex);*/
                                if (S_ISREG(inode->i_mode)) {
-                                       rc = filemap_fdatawrite(inode->i_mapping);
+                                       rc =
+                                          filemap_fdatawrite(inode->i_mapping);
                                        if (CIFS_I(inode)->clientCanCacheRead
                                                                         == 0) {
-                                               filemap_fdatawait(inode->i_mapping);
+                                               waitrc = filemap_fdatawait(inode->i_mapping);
                                                invalidate_remote_inode(inode);
                                        }
+                                       if (rc == 0)
+                                               rc = waitrc;
                                } else
                                        rc = 0;
                                /* mutex_unlock(&inode->i_mutex);*/
@@ -907,8 +949,7 @@ static int cifs_oplock_thread(void *dummyarg)
                                            0 /* len */ , 0 /* offset */, 0,
                                            0, LOCKING_ANDX_OPLOCK_RELEASE,
                                            0 /* wait flag */);
-                                       cFYI(1, 
-                                             ("Oplock release rc = %d ", rc));
+                                       cFYI(1, ("Oplock release rc = %d", rc));
                                }
                        } else
                                spin_unlock(&GlobalMid_Lock);
@@ -1009,12 +1050,21 @@ init_cifs(void)
        rc = register_filesystem(&cifs_fs_type);
        if (rc)
                goto out_destroy_request_bufs;
-
+#ifdef CONFIG_CIFS_UPCALL
+       rc = register_key_type(&cifs_spnego_key_type);
+       if (rc)
+               goto out_unregister_filesystem;
+#endif
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       rc = register_key_type(&key_type_dns_resolver);
+       if (rc)
+               goto out_unregister_key_type;
+#endif
        oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
        if (IS_ERR(oplockThread)) {
                rc = PTR_ERR(oplockThread);
                cERROR(1, ("error %d create oplock thread", rc));
-               goto out_unregister_filesystem;
+               goto out_unregister_dfs_key_type;
        }
 
        dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
@@ -1028,7 +1078,15 @@ init_cifs(void)
 
  out_stop_oplock_thread:
        kthread_stop(oplockThread);
+ out_unregister_dfs_key_type:
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       unregister_key_type(&key_type_dns_resolver);
+ out_unregister_key_type:
+#endif
+#ifdef CONFIG_CIFS_UPCALL
+       unregister_key_type(&cifs_spnego_key_type);
  out_unregister_filesystem:
+#endif
        unregister_filesystem(&cifs_fs_type);
  out_destroy_request_bufs:
        cifs_destroy_request_bufs();
@@ -1049,6 +1107,12 @@ exit_cifs(void)
        cFYI(0, ("exit_cifs"));
 #ifdef CONFIG_PROC_FS
        cifs_proc_clean();
+#endif
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       unregister_key_type(&key_type_dns_resolver);
+#endif
+#ifdef CONFIG_CIFS_UPCALL
+       unregister_key_type(&cifs_spnego_key_type);
 #endif
        unregister_filesystem(&cifs_fs_type);
        cifs_destroy_inodecache();