aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2010-10-04 22:55:57 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-05 09:08:21 -0700
commit2116b7a473bf1c8d26998b477c294e7fe294921f (patch)
tree5f06aca6b425916f763d83fa4516bca51c8f9a60 /fs
parent5af74aa5e97fcc0cc3955bc2a7ff6f3a13fa41cb (diff)
smbfs: move to drivers/staging
smbfs has been scheduled for removal in 2.6.27, so maybe we can now move it to drivers/staging on the way out. smbfs still uses the big kernel lock and nobody is going to fix that, so we should be getting rid of it soon. This removes the 32 bit compat mount and ioctl handling code, which is implemented in common fs code, and moves all smbfs related files into drivers/staging/smbfs. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig1
-rw-r--r--fs/Makefile1
-rw-r--r--fs/compat.c31
-rw-r--r--fs/compat_ioctl.c26
-rw-r--r--fs/smbfs/Kconfig55
-rw-r--r--fs/smbfs/Makefile18
-rw-r--r--fs/smbfs/cache.c208
-rw-r--r--fs/smbfs/dir.c702
-rw-r--r--fs/smbfs/file.c454
-rw-r--r--fs/smbfs/getopt.c64
-rw-r--r--fs/smbfs/getopt.h14
-rw-r--r--fs/smbfs/inode.c839
-rw-r--r--fs/smbfs/ioctl.c69
-rw-r--r--fs/smbfs/proc.c3507
-rw-r--r--fs/smbfs/proto.h87
-rw-r--r--fs/smbfs/request.c818
-rw-r--r--fs/smbfs/request.h70
-rw-r--r--fs/smbfs/smb_debug.h34
-rw-r--r--fs/smbfs/smbiod.c344
-rw-r--r--fs/smbfs/sock.c386
-rw-r--r--fs/smbfs/symlink.c68
21 files changed, 1 insertions, 7795 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 30da8ee16a9..25ce2dc1c6d 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -233,7 +233,6 @@ config NFS_COMMON
default y
source "net/sunrpc/Kconfig"
-source "fs/smbfs/Kconfig"
source "fs/ceph/Kconfig"
source "fs/cifs/Kconfig"
source "fs/ncpfs/Kconfig"
diff --git a/fs/Makefile b/fs/Makefile
index e571feddd7b..9284c74c2db 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -91,7 +91,6 @@ obj-$(CONFIG_NFSD) += nfsd/
obj-$(CONFIG_LOCKD) += lockd/
obj-$(CONFIG_NLS) += nls/
obj-$(CONFIG_SYSV_FS) += sysv/
-obj-$(CONFIG_SMB_FS) += smbfs/
obj-$(CONFIG_CIFS) += cifs/
obj-$(CONFIG_NCP_FS) += ncpfs/
obj-$(CONFIG_HPFS_FS) += hpfs/
diff --git a/fs/compat.c b/fs/compat.c
index 718c7062aec..b42f29a44ed 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -29,8 +29,6 @@
#include <linux/vfs.h>
#include <linux/ioctl.h>
#include <linux/init.h>
-#include <linux/smb.h>
-#include <linux/smb_mount.h>
#include <linux/ncp_mount.h>
#include <linux/nfs4_mount.h>
#include <linux/syscalls.h>
@@ -745,30 +743,6 @@ static void *do_ncp_super_data_conv(void *raw_data)
return raw_data;
}
-struct compat_smb_mount_data {
- compat_int_t version;
- __compat_uid_t mounted_uid;
- __compat_uid_t uid;
- __compat_gid_t gid;
- compat_mode_t file_mode;
- compat_mode_t dir_mode;
-};
-
-static void *do_smb_super_data_conv(void *raw_data)
-{
- struct smb_mount_data *s = raw_data;
- struct compat_smb_mount_data *c_s = raw_data;
-
- if (c_s->version != SMB_MOUNT_OLDVERSION)
- goto out;
- s->dir_mode = c_s->dir_mode;
- s->file_mode = c_s->file_mode;
- s->gid = c_s->gid;
- s->uid = c_s->uid;
- s->mounted_uid = c_s->mounted_uid;
- out:
- return raw_data;
-}
struct compat_nfs_string {
compat_uint_t len;
@@ -835,7 +809,6 @@ static int do_nfs4_super_data_conv(void *raw_data)
return 0;
}
-#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
#define NFS4_NAME "nfs4"
@@ -870,9 +843,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
retval = -EINVAL;
if (kernel_type && data_page) {
- if (!strcmp(kernel_type, SMBFS_NAME)) {
- do_smb_super_data_conv((void *)data_page);
- } else if (!strcmp(kernel_type, NCPFS_NAME)) {
+ if (!strcmp(kernel_type, NCPFS_NAME)) {
do_ncp_super_data_conv((void *)data_page);
} else if (!strcmp(kernel_type, NFS4_NAME)) {
if (do_nfs4_super_data_conv((void *) data_page))
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 03e59aa318e..34cf03cd791 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -46,7 +46,6 @@
#include <linux/videodev.h>
#include <linux/netdevice.h>
#include <linux/raw.h>
-#include <linux/smb_fs.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>
#include <linux/rtc.h>
@@ -558,25 +557,6 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, void __user *argp)
#endif /* CONFIG_BLOCK */
-static int do_smb_getmountuid(unsigned int fd, unsigned int cmd,
- compat_uid_t __user *argp)
-{
- mm_segment_t old_fs = get_fs();
- __kernel_uid_t kuid;
- int err;
-
- cmd = SMB_IOC_GETMOUNTUID;
-
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
- set_fs(old_fs);
-
- if (err >= 0)
- err = put_user(kuid, argp);
-
- return err;
-}
-
/* Bluetooth ioctls */
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int)
@@ -1265,8 +1245,6 @@ COMPATIBLE_IOCTL(OSS_GETVERSION)
/* Raw devices */
COMPATIBLE_IOCTL(RAW_SETBIND)
COMPATIBLE_IOCTL(RAW_GETBIND)
-/* SMB ioctls which do not need any translations */
-COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
/* Watchdog */
COMPATIBLE_IOCTL(WDIOC_GETSUPPORT)
COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
@@ -1528,10 +1506,6 @@ static long do_ioctl_trans(int fd, unsigned int cmd,
case RAW_GETBIND:
return raw_ioctl(fd, cmd, argp);
#endif
- /* One SMB ioctl needs translations. */
-#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)
- case SMB_IOC_GETMOUNTUID_32:
- return do_smb_getmountuid(fd, cmd, argp);
/* Serial */
case TIOCGSERIAL:
case TIOCSSERIAL:
diff --git a/fs/smbfs/Kconfig b/fs/smbfs/Kconfig
deleted file mode 100644
index e668127c8b2..00000000000
--- a/fs/smbfs/Kconfig
+++ /dev/null
@@ -1,55 +0,0 @@
-config SMB_FS
- tristate "SMB file system support (OBSOLETE, please use CIFS)"
- depends on INET
- select NLS
- help
- SMB (Server Message Block) is the protocol Windows for Workgroups
- (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share
- files and printers over local networks. Saying Y here allows you to
- mount their file systems (often called "shares" in this context) and
- access them just like any other Unix directory. Currently, this
- works only if the Windows machines use TCP/IP as the underlying
- transport protocol, and not NetBEUI. For details, read
- <file:Documentation/filesystems/smbfs.txt> and the SMB-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- Note: if you just want your box to act as an SMB *server* and make
- files and printing services available to Windows clients (which need
- to have a TCP/IP stack), you don't need to say Y here; you can use
- the program SAMBA (available from <ftp://ftp.samba.org/pub/samba/>)
- for that.
-
- General information about how to connect Linux, Windows machines and
- Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
-
- To compile the SMB support as a module, choose M here:
- the module will be called smbfs. Most people say N, however.
-
-config SMB_NLS_DEFAULT
- bool "Use a default NLS"
- depends on SMB_FS
- help
- Enabling this will make smbfs use nls translations by default. You
- need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls
- settings and you need to give the default nls for the SMB server as
- CONFIG_SMB_NLS_REMOTE.
-
- The nls settings can be changed at mount time, if your smbmount
- supports that, using the codepage and iocharset parameters.
-
- smbmount from samba 2.2.0 or later supports this.
-
-config SMB_NLS_REMOTE
- string "Default Remote NLS Option"
- depends on SMB_NLS_DEFAULT
- default "cp437"
- help
- This setting allows you to specify a default value for which
- codepage the server uses. If this field is left blank no
- translations will be done by default. The local codepage/charset
- default to CONFIG_NLS_DEFAULT.
-
- The nls settings can be changed at mount time, if your smbmount
- supports that, using the codepage and iocharset parameters.
-
- smbmount from samba 2.2.0 or later supports this.
diff --git a/fs/smbfs/Makefile b/fs/smbfs/Makefile
deleted file mode 100644
index 4faf8c4722c..00000000000
--- a/fs/smbfs/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the linux smb-filesystem routines.
-#
-
-obj-$(CONFIG_SMB_FS) += smbfs.o
-
-smbfs-objs := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o \
- symlink.o smbiod.o request.o
-
-# If you want debugging output, you may add these flags to the EXTRA_CFLAGS
-# SMBFS_PARANOIA should normally be enabled.
-
-EXTRA_CFLAGS += -DSMBFS_PARANOIA
-#EXTRA_CFLAGS += -DSMBFS_DEBUG
-#EXTRA_CFLAGS += -DSMBFS_DEBUG_VERBOSE
-#EXTRA_CFLAGS += -DDEBUG_SMB_TIMESTAMP
-#EXTRA_CFLAGS += -Werror
-
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c
deleted file mode 100644
index 8c177eb7e34..00000000000
--- a/fs/smbfs/cache.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * cache.c
- *
- * Copyright (C) 1997 by Bill Hawes
- *
- * Routines to support directory cacheing using the page cache.
- * This cache code is almost directly taken from ncpfs.
- *
- * Please add a note about your changes to smbfs in the ChangeLog file.
- */
-
-#include <linux/time.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smb_fs.h>
-#include <linux/pagemap.h>
-#include <linux/net.h>
-
-#include <asm/page.h>
-
-#include "smb_debug.h"
-#include "proto.h"
-
-/*
- * Force the next attempt to use the cache to be a timeout.
- * If we can't find the page that's fine, it will cause a refresh.
- */
-void
-smb_invalid_dir_cache(struct inode * dir)
-{
- struct smb_sb_info *server = server_from_inode(dir);
- union smb_dir_cache *cache = NULL;
- struct page *page = NULL;
-
- page = grab_cache_page(&dir->i_data, 0);
- if (!page)
- goto out;
-
- if (!PageUptodate(page))
- goto out_unlock;
-
- cache = kmap(page);
- cache->head.time = jiffies - SMB_MAX_AGE(server);
-
- kunmap(page);
- SetPageUptodate(page);
-out_unlock:
- unlock_page(page);
- page_cache_release(page);
-out:
- return;
-}
-
-/*
- * Mark all dentries for 'parent' as invalid, forcing them to be re-read
- */
-void
-smb_invalidate_dircache_entries(struct dentry *parent)
-{
- struct smb_sb_info *server = server_from_dentry(parent);
- struct list_head *next;
- struct dentry *dentry;
-
- spin_lock(&dcache_lock);
- next = parent->d_subdirs.next;
- while (next != &parent->d_subdirs) {
- dentry = list_entry(next, struct dentry, d_u.d_child);
- dentry->d_fsdata = NULL;
- smb_age_dentry(server, dentry);
- next = next->next;
- }
- spin_unlock(&dcache_lock);
-}
-
-/*
- * dget, but require that fpos and parent matches what the dentry contains.
- * dentry is not known to be a valid pointer at entry.
- */
-struct dentry *
-smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
-{
- struct dentry *dent = dentry;
- struct list_head *next;
-
- if (d_validate(dent, parent)) {
- if (dent->d_name.len <= SMB_MAXNAMELEN &&
- (unsigned long)dent->d_fsdata == fpos) {
- if (!dent->d_inode) {
- dput(dent);
- dent = NULL;
- }
- return dent;
- }
- dput(dent);
- }
-
- /* If a pointer is invalid, we search the dentry. */
- spin_lock(&dcache_lock);
- next = parent->d_subdirs.next;
- while (next != &parent->d_subdirs) {
- dent = list_entry(next, struct dentry, d_u.d_child);
- if ((unsigned long)dent->d_fsdata == fpos) {
- if (dent->d_inode)
- dget_locked(dent);
- else
- dent = NULL;
- goto out_unlock;
- }
- next = next->next;
- }
- dent = NULL;
-out_unlock:
- spin_unlock(&dcache_lock);
- return dent;
-}
-
-
-/*
- * Create dentry/inode for this file and add it to the dircache.
- */
-int
-smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
- struct smb_cache_control *ctrl, struct qstr *qname,
- struct smb_fattr *entry)
-{
- struct dentry *newdent, *dentry = filp->f_path.dentry;
- struct inode *newino, *inode = dentry->d_inode;
- struct smb_cache_control ctl = *ctrl;
- int valid = 0;
- int hashed = 0;
- ino_t ino = 0;
-
- qname->hash = full_name_hash(qname->name, qname->len);
-
- if (dentry->d_op && dentry->d_op->d_hash)
- if (dentry->d_op->d_hash(dentry, qname) != 0)
- goto end_advance;
-
- newdent = d_lookup(dentry, qname);
-
- if (!newdent) {
- newdent = d_alloc(dentry, qname);
- if (!newdent)
- goto end_advance;
- } else {
- hashed = 1;
- memcpy((char *) newdent->d_name.name, qname->name,
- newdent->d_name.len);
- }
-
- if (!newdent->d_inode) {
- smb_renew_times(newdent);
- entry->f_ino = iunique(inode->i_sb, 2);
- newino = smb_iget(inode->i_sb, entry);
- if (newino) {
- smb_new_dentry(newdent);
- d_instantiate(newdent, newino);
- if (!hashed)
- d_rehash(newdent);
- }
- } else
- smb_set_inode_attr(newdent->d_inode, entry);
-
- if (newdent->d_inode) {
- ino = newdent->d_inode->i_ino;
- newdent->d_fsdata = (void *) ctl.fpos;
- smb_new_dentry(newdent);
- }
-
- if (ctl.idx >= SMB_DIRCACHE_SIZE) {
- if (ctl.page) {
- kunmap(ctl.page);
- SetPageUptodate(ctl.page);
- unlock_page(ctl.page);
- page_cache_release(ctl.page);
- }
- ctl.cache = NULL;
- ctl.idx -= SMB_DIRCACHE_SIZE;
- ctl.ofs += 1;
- ctl.page = grab_cache_page(&inode->i_data, ctl.ofs);
- if (ctl.page)
- ctl.cache = kmap(ctl.page);
- }
- if (ctl.cache) {
- ctl.cache->dentry[ctl.idx] = newdent;
- valid = 1;
- }
- dput(newdent);
-
-end_advance:
- if (!valid)
- ctl.valid = 0;
- if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
- if (!ino)
- ino = find_inode_number(dentry, qname);
- if (!ino)
- ino = iunique(inode->i_sb, 2);
- ctl.filled = filldir(dirent, qname->name, qname->len,
- filp->f_pos, ino, DT_UNKNOWN);
- if (!ctl.filled)
- filp->f_pos += 1;
- }
- ctl.fpos += 1;
- ctl.idx += 1;
- *ctrl = ctl;
- return (ctl.valid || !ctl.filled);
-}
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
deleted file mode 100644
index 00a70cab1f3..00000000000
--- a/fs/smbfs/dir.c
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
- * dir.c
- *
- * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
- * Copyright (C) 1997 by Volker Lendecke
- *
- * Please add a note about your changes to smbfs in the ChangeLog file.
- */
-
-#include <linux/time.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/smp_lock.h>
-#include <linux/ctype.h>
-#include <linux/net.h>
-#include <linux/sched.h>
-
-#include <linux/smb_fs.h>
-#include <linux/smb_mount.h>
-#include <linux/smbno.h>
-
-#include "smb_debug.h"
-#include "proto.h"
-
-static int smb_readdir(struct file *, void *, filldir_t);
-static int smb_dir_open(struct inode *, struct file *);
-
-static struct dentry *smb_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int smb_create(struct inode *, struct dentry *, int, struct nameidata *);
-static int smb_mkdir(struct inode *, struct dentry *, int);
-static int smb_rmdir(struct inode *, struct dentry *);
-static int smb_unlink(struct inode *, struct dentry *);
-static int smb_rename(struct inode *, struct dentry *,
- struct inode *, struct dentry *);
-static int smb_make_node(struct inode *,struct dentry *,int,dev_t);
-static int smb_link(struct dentry *, struct inode *, struct dentry *);
-
-const struct file_operations smb_dir_operations =
-{
- .llseek = generic_file_llseek,
- .read = generic_read_dir,
- .readdir = smb_readdir,
- .unlocked_ioctl = smb_ioctl,
- .open = smb_dir_open,
-};
-
-const struct inode_operations smb_dir_inode_operations =
-{
- .create = smb_create,
- .lookup = smb_lookup,
- .unlink = smb_unlink,
- .mkdir = smb_mkdir,
- .rmdir = smb_rmdir,
- .rename = smb_rename,
- .getattr = smb_getattr,
- .setattr = smb_notify_change,
-};
-
-const struct inode_operations smb_dir_inode_operations_unix =
-{
- .create = smb_create,
- .lookup = smb_lookup,
- .unlink = smb_unlink,
- .mkdir = smb_mkdir,
- .rmdir = smb_rmdir,
- .rename = smb_rename,
- .getattr = smb_getattr,
- .setattr = smb_notify_change,
- .symlink = smb_symlink,
- .mknod = smb_make_node,
- .link = smb_link,
-};
-
-/*
- * Read a directory, using filldir to fill the dirent memory.
- * smb_proc_readdir does the actual reading from the smb server.
- *
- * The cache code is almost directly taken from ncpfs
- */
-static int
-smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
-{
- struct dentry *dentry = filp->f_path.dentry;
- struct inode *dir = dentry->d_inode;
- struct smb_sb_info *server = server_from_dentry(dentry);
- union smb_dir_cache *cache = NULL;
- struct smb_cache_control ctl;
- struct page *page = NULL;
- int result;
-
- ctl.page = NULL;
- ctl.cache = NULL;
-
- VERBOSE("reading %s/%s, f_pos=%d\n",
- DENTRY_PATH(dentry), (int) filp->f_pos);
-
- result = 0;
-
- lock_kernel();
-
- switch ((unsigned int) filp->f_pos) {
- case 0:
- if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
- goto out;
- filp->f_pos = 1;
- /* fallthrough */
- case 1:
- if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR) < 0)
- goto out;
- filp->f_pos = 2;
- }
-
- /*
- * Make sure our inode is up-to-date.
- */
- result = smb_revalidate_inode(dentry);
- if (result)
- goto out;
-
-
- page = grab_cache_page(&dir->i_data, 0);
- if (!page)
- goto read_really;
-
- ctl.cache = cache = kmap(page);
- ctl.head = cache->head;
-
- if (!PageUptodate(page) || !ctl.head.eof) {
- VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",
- DENTRY_PATH(dentry), PageUptodate(page),ctl.head.eof);
- goto init_cache;
- }
-
- if (filp->f_pos == 2) {
- if (jiffies - ctl.head.time >= SMB_MAX_AGE(server))
- goto init_cache;
-
- /*
- * N.B. ncpfs checks mtime of dentry too here, we don't.
- * 1. common smb servers do not update mtime on dir changes
- * 2. it requires an extra smb request
- * (revalidate has the same timeout as ctl.head.time)
- *
- * Instead smbfs invalidates its own cache on local changes
- * and remote changes are not seen until timeout.
- */
- }
-
- if (filp->f_pos > ctl.head.end)
- goto finished;
-
- ctl.fpos = filp->f_pos + (SMB_DIRCACHE_START - 2);
- ctl.ofs = ctl.fpos / SMB_DIRCACHE_SIZE;
- ctl.idx = ctl.fpos % SMB_DIRCACHE_SIZE;
-
- for (;;) {
- if (ctl.ofs != 0) {
- ctl.page = find_lock_page(&dir->i_data, ctl.ofs);
- if (!ctl.page)
- goto invalid_cache;
- ctl.cache = kmap(ctl.page);
- if (!PageUptodate(ctl.page))
- goto invalid_cache;
- }
- while (ctl.idx < SMB_DIRCACHE_SIZE) {
- struct dentry *dent;
- int res;
-
- dent = smb_dget_fpos(ctl.cache->dentry[ctl.idx],
- dentry, filp->f_pos);
- if (!dent)
- goto invalid_cache;
-
- res = filldir(dirent, dent->d_name.name,
- dent->d_name.len, filp->f_pos,
- dent->d_inode->i_ino, DT_UNKNOWN);
- dput(dent);
- if (res)
- goto finished;
- filp->f_pos += 1;
- ctl.idx += 1;
- if (filp->f_pos > ctl.head.end)
- goto finished;
- }
- if (ctl.page) {
- kunmap(ctl.page);
- SetPageUptodate(ctl.page);
- unlock_page(ctl.page);
- page_cache_release(ctl.page);
- ctl.page = NULL;
- }
- ctl.idx = 0;
- ctl.ofs += 1;
- }
-invalid_cache:
- if (ctl.page) {
- kunmap(ctl.page);
- unlock_page(ctl.page);
- page_cache_release(ctl.page);
- ctl.page = NULL;
- }
- ctl.cache = cache;
-init_cache:
- smb_invalidate_dircache_entries(dentry);
- ctl.head.time = jiffies;
- ctl.head.eof = 0;
- ctl.fpos = 2;
- ctl.ofs = 0;
- ctl.idx = SMB_DIRCACHE_START;
- ctl.filled = 0;
- ctl.valid = 1;
-read_really:
- result = server->ops->readdir(filp, dirent, filldir, &ctl);
- if (result == -ERESTARTSYS && page)
- ClearPageUptodate(page);
- if (ctl.idx == -1)
- goto invalid_cache; /* retry */
- ctl.head.end = ctl.fpos - 1;
- ctl.head.eof = ctl.valid;
-finished:
- if (page) {
- cache->head = ctl.head;
- kunmap(page);
- if (result != -ERESTARTSYS)
- SetPageUptodate(page);
- unlock_page(page);
- page_cache_release(page);
- }
- if (ctl.page) {
- kunmap(ctl.page);
- SetPageUptodate(ctl.page);
- unlock_page(ctl.page);
- page_cache_release(ctl.page);
- }
-out:
- unlock_kernel();
- return result;
-}
-
-static int
-smb_dir_open(struct inode *dir, struct file *file)
-{
- struct dentry *dentry = file->f_path.dentry;
- struct smb_sb_info *server;
- int error = 0;
-
- VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,
- file->f_path.dentry->d_name.name);
-
- /*
- * Directory timestamps in the core protocol aren't updated
- * when a file is added, so we give them a very short TTL.
- */
- lock_kernel();
- server = server_from_dentry(dentry);
- if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) {
- unsigned long age = jiffies - SMB_I(dir)->oldmtime;
- if (age > 2*HZ)
- smb_invalid_dir_cache(dir);
- }
-
- /*
- * Note: in order to allow the smbmount process to open the
- * mount point, we only revalidate if the connection is valid or
- * if the process is trying to access something other than the root.
- */
- if (server->state == CONN_VALID || !IS_ROOT(dentry))
- error = smb_revalidate_inode(dentry);
- unlock_kernel();
- return error;
-}
-
-/*
- * Dentry operations routines
- */
-static int smb_lookup_validate(struct dentry *, struct nameidata *);
-static int smb_hash_dentry(struct dentry *, struct qstr *);
-static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
-static int smb_delete_dentry(struct dentry *);
-
-static const struct dentry_operations smbfs_dentry_operations =
-{
- .d_revalidate = smb_lookup_validate,
- .d_hash = smb_hash_dentry,
- .d_compare = smb_compare_dentry,
- .d_delete = smb_delete_dentry,
-};
-
-static const struct dentry_operations smbfs_dentry_operations_case =
-{
- .d_revalidate = smb_lookup_validate,
- .d_delete = smb_delete_dentry,
-};
-
-
-/*
- * This is the callback when the dcache has a lookup hit.
- */
-static int
-smb_lookup_validate(struct dentry * dentry, struct nameidata *nd)
-{
- struct smb_sb_info *server = server_from_dentry(dentry);
- struct inode * inode = dentry->d_inode;
- unsigned long age = jiffies - dentry->d_time;
- int valid;
-
- /*
- * The default validation is based on dentry age:
- * we believe in dentries for a few seconds. (But each
- * successful server lookup renews the timestamp.)
- */
- valid = (age <= SMB_MAX_AGE(server));
-#ifdef SMBFS_DEBUG_VERBOSE
- if (!valid)
- VERBOSE("%s/%s not valid, age=%lu\n",
- DENTRY_PATH(dentry), age);
-#endif
-
- if (inode) {
- lock_kernel();
- if (is_bad_inode(inode)) {
- PARANOIA("%s/%s has dud inode\n", DENTRY_PATH(dentry));
- valid = 0;
- } else if (!valid)
- valid = (smb_revalidate_inode(dentry) == 0);
- unlock_kernel();
- } else {
- /*
- * What should we do for negative dentries?
- */
- }
- return valid;
-}
-
-static int
-smb_hash_dentry(struct dentry *dir, struct qstr *this)
-{
- unsigned long hash;
- int i;
-
- hash = init_name_hash();
- for (i=0; i < this->len ; i++)
- hash = partial_name_hash(tolower(this->name[i]), hash);
- this->hash = end_name_hash(hash);
-
- return 0;
-}
-
-static int
-smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b)
-{
- int i, result = 1;
-
- if (a->len != b->len)
- goto out;
- for (i=0; i < a->len; i++) {
- if (tolower(a->name[i]) != tolower(b->name[i]))
- goto out;
- }
- result = 0;
-out:
- return result;
-}
-
-/*
- * This is the callback from dput() when d_count is going to 0.
- * We use this to unhash dentries with bad inodes.
- */
-static int
-smb_delete_dentry(struct dentry * dentry)
-{
- if (dentry->d_inode) {
- if (is_bad_inode(dentry->d_inode)) {
- PARANOIA("bad inode, unhashing %s/%s\n",
- DENTRY_PATH(dentry));
- return 1;
- }
- } else {
- /* N.B. Unhash negative dentries? */
- }
- return 0;
-}
-
-/*
- * Initialize a new dentry
- */
-void
-smb_new_dentry(struct dentry *dentry)
-{
- struct smb_sb_info *server = server_from_dentry(dentry);
-
- if (server->mnt->flags & SMB_MOUNT_CASE)
- dentry->d_op = &smbfs_dentry_operations_case;
- else
- dentry->d_op = &smbfs_dentry_operations;
- dentry->d_time = jiffies;
-}
-
-
-/*
- * Whenever a lookup succeeds, we know the parent directories
- * are all valid, so we want to update the dentry timestamps.
- * N.B. Move this to dcache?
- */
-void
-smb_renew_times(struct dentry * dentry)
-{
- dget(dentry);
- spin_lock(&dentry->d_lock);
- for (;;) {
- struct dentry *parent;
-
- dentry->d_time = jiffies;
- if (IS_ROOT(dentry))
- break;
- parent = dentry->d_parent;
- dget(parent);
- spin_unlock(&dentry->d_lock);
- dput(dentry);
- dentry = parent;
- spin_lock(&dentry->d_lock);
- }
- spin_unlock(&dentry->d_lock);
- dput(dentry);
-}
-
-static struct dentry *
-smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
-{
- struct smb_fattr finfo;
- struct inode *inode;
- int error;
- struct smb_sb_info *server;
-
- error = -ENAMETOOLONG;
- if (dentry->d_name.len > SMB_MAXNAMELEN)
- goto out;
-
- /* Do not allow lookup of names with backslashes in */
- error = -EINVAL;
- if (memchr(dentry->d_name.name, '\\', dentry->d_name.len))
- goto out;
-
- lock_kernel();
- error = smb_proc_getattr(dentry, &finfo);
-#ifdef SMBFS_PARANOIA
- if (error && error != -ENOENT)
- PARANOIA("find %s/%s failed, error=%d\n",
- DENTRY_PATH(dentry), error);
-#endif
-
- inode = NULL;
- if (error == -ENOENT)
- goto add_entry;
- if (!error) {
- error = -EACCES;
- finfo.f_ino = iunique(dentry->d_sb, 2);
- inode = smb_iget(dir->i_sb, &finfo);
- if (inode) {
- add_entry:
- server = server_from_dentry(dentry);
- if (server->mnt->flags & SMB_MOUNT_CASE)
- dentry->d_op = &smbfs_dentry_operations_case;
- else
- dentry->d_op = &smbfs_dentry_operations;
-
- d_add(dentry, inode);
- smb_renew_times(dentry);
- error = 0;
- }
- }
- unlock_kernel();
-out:
- return ERR_PTR(error);
-}
-
-/*
- * This code is common to all routines creating a new inode.
- */
-static int
-smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
-{
- struct smb_sb_info *server = server_from_dentry(dentry);
- struct inode *inode;
- int error;
- struct smb_fattr fattr;
-
- VERBOSE("file %s/%s, fileid=%u\n", DENTRY_PATH(dentry), fileid);
-
- error = smb_proc_getattr(dentry, &fattr);
- if (error)
- goto out_close;
-
- smb_renew_times(dentry);
- fattr.f_ino = iunique(dentry->d_sb, 2);
- inode = smb_iget(dentry->d_sb, &fattr);
- if (!inode)
- goto out_no_inode;
-
- if (have_id) {
- struct smb_inode_info *ei = SMB_I(inode);
- ei->fileid = fileid;
- ei->access = SMB_O_RDWR;
- ei->open = server->generation;
- }
- d_instantiate(dentry, inode);
-out:
- return error;
-
-out_no_inode:
- error = -EACCES;
-out_close:
- if (have_id) {
- PARANOIA("%s/%s failed, error=%d, closing %u\n",
- DENTRY_PATH(dentry), error, fileid);
- smb_close_fileid(dentry, fileid);
- }
- goto out;
-}
-
-/* N.B. How should the mode argument be used? */
-static int
-smb_create(struct inode *dir, struct dentry *dentry, int mode,
- struct nameidata *nd)
-{
- struct smb_sb_info *server = server_from_dentry(dentry);
- __u16 fileid;
- int error;
- struct iattr attr;
-
- VERBOSE("creating %s/%s, mode=%d\n", DENTRY_PATH(dentry), mode);
-
- lock_kernel();
- smb_invalid_dir_cache(dir);
- error = smb_proc_create(dentry, 0, get_seconds(), &fileid);
- if (!error) {
- if (server->opt.capabilities & SMB_CAP_UNIX) {
- /* Set attributes for new file */
- attr.ia_valid = ATTR_MODE;
- attr.ia_mode = mode;
- error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
- }
- error = smb_instantiate(dentry, fileid, 1);
- } else {
- PARANOIA("%s/%s failed, error=%d\n",
- DENTRY_PATH(dentry), error);
- }
- unlock_kernel();
- return error;
-}
-
-/* N.B. How should the mode argument be used? */
-static int
-smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
- struct smb_sb_info *server = server_from_dentry(dentry);
- int error;
- struct iattr attr;
-
- lock_kernel();
- smb_invalid_dir_cache(dir);
- error = smb_proc_mkdir(dentry);
- if (!error) {
- if (server->opt.capabilities & SMB_CAP_UNIX) {
- /* Set attributes for new directory */
- attr.ia_valid = ATTR_MODE;
- attr.ia_mode = mode;
- error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
- }
- error = smb_instantiate(dentry, 0, 0);
- }
- unlock_kernel();
- return error;