unsigned int sign_CIFS_PDUs = 1;
extern struct task_struct * oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL;
+extern struct task_struct * dnotifyThread; /* remove sparse warning */
+struct task_struct * dnotifyThread = NULL;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0);
MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
static DECLARE_COMPLETION(cifs_oplock_exited);
+static DECLARE_COMPLETION(cifs_dnotify_exited);
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
static int
cifs_statfs(struct super_block *sb, struct kstatfs *buf)
{
- int xid, rc = -EOPNOTSUPP;
+ int xid;
+ int rc = -EOPNOTSUPP;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
buf->f_type = CIFS_MAGIC_NUMBER;
/* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
- buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably
- be length of total path, note that some servers may be
- able to support more than this, but best to be safe
- since Win2k and others can not handle very long filenames */
+ buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would
+ presumably be total path, but note
+ that some servers (includinng Samba 3)
+ have a shorter maximum path */
buf->f_files = 0; /* undefined */
buf->f_ffree = 0; /* unlimited */
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* BB we could add a second check for a QFS Unix capability bit */
- if (pTcon->ses->capabilities & CAP_UNIX)
- rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf, cifs_sb->local_nls);
+/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
+ if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS &
+ le64_to_cpu(pTcon->fsUnixInfo.Capability)))
+ rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf);
/* Only need to call the old QFSInfo if failed
on newer one */
if(rc)
#endif /* CIFS_EXPERIMENTAL */
- rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls);
+ rc = CIFSSMBQFSInfo(xid, pTcon, buf);
+ /* Old Windows servers do not support level 103, retry with level
+ one if old server failed the previous call */
+ if(rc)
+ rc = SMBOldQFSInfo(xid, pTcon, buf);
/*
int f_type;
__fsid_t f_fsid;
int f_namelen; */
- /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */
+ /* BB get from info in tcon struct at mount time call to QFSAttrInfo */
FreeXid(xid);
- return 0; /* always return success? what if volume is no longer available? */
+ return 0; /* always return success? what if volume is no
+ longer available? */
}
static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
cifs_inode->clientCanCacheAll = FALSE;
cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
-
+ cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
INIT_LIST_HEAD(&cifs_inode->openFileList);
return &cifs_inode->vfs_inode;
}
};
#endif
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+static void cifs_umount_begin(struct super_block * sblock)
+{
+ struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo * tcon;
+
+ cifs_sb = CIFS_SB(sblock);
+ if(cifs_sb == NULL)
+ return;
+
+ tcon = cifs_sb->tcon;
+ if(tcon == NULL)
+ return;
+ down(&tcon->tconSem);
+ if (atomic_read(&tcon->useCount) == 1)
+ tcon->tidStatus = CifsExiting;
+ up(&tcon->tconSem);
+
+ /* cancel_brl_requests(tcon); */
+ /* cancel_notify_requests(tcon); */
+ if(tcon->ses && tcon->ses->server)
+ {
+ cFYI(1,("wake up tasks now - umount begin not complete"));
+ wake_up_all(&tcon->ses->server->request_q);
+ }
+/* BB FIXME - finish add checks for tidStatus BB */
+
+ return;
+}
+#endif
+
static int cifs_remount(struct super_block *sb, int *flags, char *data)
{
*flags |= MS_NODIRATIME;
unless later we add lazy close of inodes or unless the kernel forgets to call
us with the same number of releases (closes) as opens */
.show_options = cifs_show_options,
-/* .umount_begin = cifs_umount_begin, *//* consider adding in the future */
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+ .umount_begin = cifs_umount_begin,
+#endif
.remount_fs = cifs_remount,
};
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.sendfile = generic_file_sendfile,
+#ifdef CONFIG_CIFS_POSIX
+ .ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
#ifdef CONFIG_CIFS_EXPERIMENTAL
.readv = generic_file_readv,
.writev = generic_file_writev,
.fsync = cifs_fsync,
.flush = cifs_flush,
.sendfile = generic_file_sendfile, /* BB removeme BB */
+#ifdef CONFIG_CIFS_POSIX
+ .ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
+struct file_operations cifs_file_nobrl_ops = {
+ .read = cifs_read_wrapper,
+ .write = cifs_write_wrapper,
+ .open = cifs_open,
+ .release = cifs_close,
+ .fsync = cifs_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_mmap,
+ .sendfile = generic_file_sendfile,
+#ifdef CONFIG_CIFS_POSIX
+ .ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+ .readv = generic_file_readv,
+ .writev = generic_file_writev,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .dir_notify = cifs_dir_notify,
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
+};
+
+struct file_operations cifs_file_direct_nobrl_ops = {
+ /* no mmap, no aio, no readv -
+ BB reevaluate whether they can be done with directio, no cache */
+ .read = cifs_user_read,
+ .write = cifs_user_write,
+ .open = cifs_open,
+ .release = cifs_close,
+ .fsync = cifs_fsync,
+ .flush = cifs_flush,
+ .sendfile = generic_file_sendfile, /* BB removeme BB */
+#ifdef CONFIG_CIFS_POSIX
+ .ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+ .dir_notify = cifs_dir_notify,
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
+};
struct file_operations cifs_dir_ops = {
.readdir = cifs_readdir,
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
+ .ioctl = cifs_ioctl,
};
static void
oplockThread = current;
do {
- set_current_state(TASK_INTERRUPTIBLE);
+ if (try_to_freeze())
+ continue;
- schedule_timeout(1*HZ);
spin_lock(&GlobalMid_Lock);
if(list_empty(&GlobalOplock_Q)) {
spin_unlock(&GlobalMid_Lock);
}
} else
spin_unlock(&GlobalMid_Lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1); /* yield in case q were corrupt */
}
} while(!signal_pending(current));
+ oplockThread = NULL;
complete_and_exit (&cifs_oplock_exited, 0);
}
+static int cifs_dnotify_thread(void * dummyarg)
+{
+ daemonize("cifsdnotifyd");
+ allow_signal(SIGTERM);
+
+ dnotifyThread = current;
+ do {
+ if(try_to_freeze())
+ continue;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(39*HZ);
+ } while(!signal_pending(current));
+ complete_and_exit (&cifs_dnotify_exited, 0);
+}
+
static int __init
init_cifs(void)
{
INIT_LIST_HEAD(&GlobalSMBSessionList);
INIT_LIST_HEAD(&GlobalTreeConnectionList);
INIT_LIST_HEAD(&GlobalOplock_Q);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+ INIT_LIST_HEAD(&GlobalDnotifyReqList);
+ INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
+#endif
/*
* Initialize Global counters
*/
if (!rc) {
rc = (int)kernel_thread(cifs_oplock_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_VM);
- if(rc > 0)
- return 0;
- else
+ if(rc > 0) {
+ rc = (int)kernel_thread(cifs_dnotify_thread, NULL,
+ CLONE_FS | CLONE_FILES | CLONE_VM);
+ if(rc > 0)
+ return 0;
+ else
+ cERROR(1,("error %d create dnotify thread", rc));
+ } else {
cERROR(1,("error %d create oplock thread",rc));
+ }
}
cifs_destroy_request_bufs();
}
send_sig(SIGTERM, oplockThread, 1);
wait_for_completion(&cifs_oplock_exited);
}
+ if(dnotifyThread) {
+ send_sig(SIGTERM, dnotifyThread, 1);
+ wait_for_completion(&cifs_dnotify_exited);
+ }
}
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");