[PATCH] move executable checking into ->permission()
[safe/jmp/linux-2.6] / fs / cifs / cifsfs.c
index 427a7c6..84cc011 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsfs.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2007
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Common Internet FileSystem (CIFS) client
@@ -97,9 +97,6 @@ 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? */
@@ -117,15 +114,17 @@ cifs_read_super(struct super_block *sb, void *data,
         * 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;
+       if (data) {
+               int 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';
        }
-       strncpy(cifs_sb->mountdata, data, len + 1);
-       cifs_sb->mountdata[len] = '\0';
 #endif
 
        rc = cifs_mount(sb, cifs_sb, data, devname);
@@ -176,6 +175,8 @@ out_no_root:
        if (inode)
                iput(inode);
 
+       cifs_umount(sb, cifs_sb);
+
 out_mount_failed:
        if (cifs_sb) {
 #ifdef CONFIG_CIFS_DFS_UPCALL
@@ -268,15 +269,18 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
-static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
+static int cifs_permission(struct inode *inode, int mask)
 {
        struct cifs_sb_info *cifs_sb;
 
        cifs_sb = CIFS_SB(inode->i_sb);
 
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
-               return 0;
-       else /* file mode might have been restricted at mount time
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
+               if ((mask & MAY_EXEC) && !execute_ok(inode))
+                       return -EACCES;
+               else
+                       return 0;
+       } 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 */
@@ -353,9 +357,41 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
                        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->tcon->unix_ext) {
+                               seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
+                                          cifs_sb->mnt_file_mode,
+                                          cifs_sb->mnt_dir_mode);
+                       }
+                       if (cifs_sb->tcon->seal)
+                               seq_printf(s, ",seal");
+                       if (cifs_sb->tcon->nocase)
+                               seq_printf(s, ",nocase");
+                       if (cifs_sb->tcon->retry)
+                               seq_printf(s, ",hard");
                }
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
                        seq_printf(s, ",posixpaths");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
+                       seq_printf(s, ",setuids");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+                       seq_printf(s, ",serverino");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+                       seq_printf(s, ",directio");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+                       seq_printf(s, ",nouser_xattr");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+                       seq_printf(s, ",mapchars");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+                       seq_printf(s, ",sfu");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                       seq_printf(s, ",nobrl");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
+                       seq_printf(s, ",cifsacl");
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+                       seq_printf(s, ",dynperm");
+               if (m->mnt_sb->s_flags & MS_POSIXACL)
+                       seq_printf(s, ",acl");
+
                seq_printf(s, ",rsize=%d", cifs_sb->rsize);
                seq_printf(s, ",wsize=%d", cifs_sb->wsize);
        }
@@ -581,7 +617,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
                if (retval < 0)
                        return (loff_t)retval;
        }
-       return remote_llseek(file, offset, origin);
+       return generic_file_llseek_unlocked(file, offset, origin);
 }
 
 struct file_system_type cifs_fs_type = {
@@ -657,7 +693,7 @@ const struct file_operations cifs_file_ops = {
        .splice_read = generic_file_splice_read,
        .llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_POSIX
-       .ioctl  = cifs_ioctl,
+       .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -677,7 +713,7 @@ const struct file_operations cifs_file_direct_ops = {
        .flush = cifs_flush,
        .splice_read = generic_file_splice_read,
 #ifdef CONFIG_CIFS_POSIX
-       .ioctl  = cifs_ioctl,
+       .unlocked_ioctl  = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -697,7 +733,7 @@ const struct file_operations cifs_file_nobrl_ops = {
        .splice_read = generic_file_splice_read,
        .llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_POSIX
-       .ioctl  = cifs_ioctl,
+       .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -716,7 +752,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
        .flush = cifs_flush,
        .splice_read = generic_file_splice_read,
 #ifdef CONFIG_CIFS_POSIX
-       .ioctl  = cifs_ioctl,
+       .unlocked_ioctl  = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .llseek = cifs_llseek,
 #ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -731,11 +767,12 @@ const struct file_operations cifs_dir_ops = {
 #ifdef CONFIG_CIFS_EXPERIMENTAL
        .dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
-       .ioctl  = cifs_ioctl,
+       .unlocked_ioctl  = cifs_ioctl,
+       .llseek = generic_file_llseek,
 };
 
 static void
-cifs_init_once(struct kmem_cache *cachep, void *inode)
+cifs_init_once(void *inode)
 {
        struct cifsInodeInfo *cifsi = inode;
 
@@ -899,36 +936,34 @@ static int cifs_oplock_thread(void *dummyarg)
                        schedule_timeout(39*HZ);
                } else {
                        oplock_item = list_entry(GlobalOplock_Q.next,
-                               struct oplock_q_entry, qhead);
-                       if (oplock_item) {
-                               cFYI(1, ("found oplock item to write out"));
-                               pTcon = oplock_item->tcon;
-                               inode = oplock_item->pinode;
-                               netfid = oplock_item->netfid;
-                               spin_unlock(&GlobalMid_Lock);
-                               DeleteOplockQEntry(oplock_item);
-                               /* can not grab inode sem here since it would
+                                               struct oplock_q_entry, qhead);
+                       cFYI(1, ("found oplock item to write out"));
+                       pTcon = oplock_item->tcon;
+                       inode = oplock_item->pinode;
+                       netfid = oplock_item->netfid;
+                       spin_unlock(&GlobalMid_Lock);
+                       DeleteOplockQEntry(oplock_item);
+                       /* can not grab inode sem here since it would
                                deadlock when oplock received on delete
                                since vfs_unlink holds the i_mutex across
                                the call */
-                               /* mutex_lock(&inode->i_mutex);*/
-                               if (S_ISREG(inode->i_mode)) {
-                                       rc =
-                                          filemap_fdatawrite(inode->i_mapping);
-                                       if (CIFS_I(inode)->clientCanCacheRead
-                                                                        == 0) {
-                                               waitrc = filemap_fdatawait(inode->i_mapping);
-                                               invalidate_remote_inode(inode);
-                                       }
-                                       if (rc == 0)
-                                               rc = waitrc;
-                               } else
-                                       rc = 0;
-                               /* mutex_unlock(&inode->i_mutex);*/
-                               if (rc)
-                                       CIFS_I(inode)->write_behind_rc = rc;
-                               cFYI(1, ("Oplock flush inode %p rc %d",
-                                       inode, rc));
+                       /* mutex_lock(&inode->i_mutex);*/
+                       if (S_ISREG(inode->i_mode)) {
+                               rc = filemap_fdatawrite(inode->i_mapping);
+                               if (CIFS_I(inode)->clientCanCacheRead == 0) {
+                                       waitrc = filemap_fdatawait(
+                                                             inode->i_mapping);
+                                       invalidate_remote_inode(inode);
+                               }
+                               if (rc == 0)
+                                       rc = waitrc;
+                       } else
+                               rc = 0;
+                       /* mutex_unlock(&inode->i_mutex);*/
+                       if (rc)
+                               CIFS_I(inode)->write_behind_rc = rc;
+                       cFYI(1, ("Oplock flush inode %p rc %d",
+                               inode, rc));
 
                                /* releasing stale oplock after recent reconnect
                                of smb session using a now incorrect file
@@ -936,15 +971,13 @@ static int cifs_oplock_thread(void *dummyarg)
                                not bother sending an oplock release if session
                                to server still is disconnected since oplock
                                already released by the server in that case */
-                               if (pTcon->tidStatus != CifsNeedReconnect) {
-                                   rc = CIFSSMBLock(0, pTcon, netfid,
-                                           0 /* len */ , 0 /* offset */, 0,
-                                           0, LOCKING_ANDX_OPLOCK_RELEASE,
-                                           false /* wait flag */);
-                                       cFYI(1, ("Oplock release rc = %d", rc));
-                               }
-                       } else
-                               spin_unlock(&GlobalMid_Lock);
+                       if (pTcon->tidStatus != CifsNeedReconnect) {
+                               rc = CIFSSMBLock(0, pTcon, netfid,
+                                               0 /* len */ , 0 /* offset */, 0,
+                                               0, LOCKING_ANDX_OPLOCK_RELEASE,
+                                               false /* wait flag */);
+                               cFYI(1, ("Oplock release rc = %d", rc));
+                       }
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule_timeout(1);  /* yield in case q were corrupt */
                }
@@ -970,8 +1003,7 @@ static int cifs_dnotify_thread(void *dummyarg)
                list_for_each(tmp, &GlobalSMBSessionList) {
                        ses = list_entry(tmp, struct cifsSesInfo,
                                cifsSessionList);
-                       if (ses && ses->server &&
-                            atomic_read(&ses->server->inFlight))
+                       if (ses->server && atomic_read(&ses->server->inFlight))
                                wake_up_all(&ses->server->response_q);
                }
                read_unlock(&GlobalSMBSeslock);