Commit f59dfe26 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.58

parent b23c7003
......@@ -632,8 +632,9 @@ S: USA
N: Nick Holloway
E: Nick.Holloway@alfie.demon.co.uk
E: Nick.Holloway@parallax.co.uk
D: Small patches for kernel, libc
D: MAKEDEV
W: http://www.alfie.demon.co.uk/
P: 1024/75C49395 3A F0 E3 4E B7 9F E0 7E 47 A3 B0 D5 68 6A C2 FB
D: Occasional Linux hacker...
S: 15 Duke Street
S: Chapelfields
S: Coventry
......
VERSION = 2
PATCHLEVEL = 1
SUBLEVEL = 57
SUBLEVEL = 58
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
......
......@@ -172,9 +172,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
/* Are we prepared to handle this kernel fault? */
if ((fixup = search_exception_table(regs->eip)) != 0) {
printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
printk(KERN_DEBUG "%s: Exception at [<%lx>] cr2=%lx (fixup: %lx)\n",
tsk->comm,
regs->eip,
address,
fixup);
regs->eip = fixup;
goto out;
......
......@@ -19,7 +19,7 @@ static struct dentry * bad_follow_link(struct inode * ino, struct dentry *base)
return ERR_PTR(-EIO);
}
static int return_EIO()
static int return_EIO(void)
{
return -EIO;
}
......@@ -81,3 +81,12 @@ void make_bad_inode(struct inode * inode)
inode->i_op = &bad_inode_ops;
}
/*
* This tests whether an inode has been flagged as bad. The test uses
* &bad_inode_ops to cover the case of invalidated inodes as well as
* those created by make_bad_inode() above.
*/
int is_bad_inode(struct inode * inode)
{
return (inode->i_op == &bad_inode_ops);
}
......@@ -281,21 +281,19 @@ static int proc_write_register(struct file *file, const char *buffer,
const char *sp;
char del, *dp;
struct binfmt_entry *e;
int memsize, cnt = count - 1, err = 0;
int memsize, cnt = count - 1, err;
MOD_INC_USE_COUNT;
/* some sanity checks */
if ((count < 11) || (count > 256)) {
err = -EINVAL;
if ((count < 11) || (count > 256))
goto _err;
}
memsize = sizeof(struct binfmt_entry) + count;
if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
err = -ENOMEM;
memsize = sizeof(struct binfmt_entry) + count;
if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
goto _err;
}
err = 0;
sp = buffer + 1;
del = buffer[0];
dp = (char *)e + sizeof(struct binfmt_entry);
......@@ -327,12 +325,8 @@ static int proc_write_register(struct file *file, const char *buffer,
/* more sanity checks */
if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
(e->size < 1) || ((e->size + e->offset) > 127) ||
!(e->proc_name) || !(e->interpreter) ||
entry_proc_setup(e)) {
kfree(e);
err = -EINVAL;
goto _err;
}
!(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
goto free_err;
write_lock(&entries_lock);
e->next = entries;
......@@ -341,8 +335,11 @@ static int proc_write_register(struct file *file, const char *buffer,
err = count;
_err:
MOD_DEC_USE_COUNT;
return err;
free_err:
kfree(e);
err = -EINVAL;
goto _err;
}
/*
......@@ -357,7 +354,6 @@ static int proc_read_status(char *page, char **start, off_t off,
char *dp;
int elen, i, err;
MOD_INC_USE_COUNT;
#ifndef VERBOSE_STATUS
if (data) {
if (!(e = get_entry((int) data))) {
......@@ -415,7 +411,6 @@ static int proc_read_status(char *page, char **start, off_t off,
err = elen;
_err:
MOD_DEC_USE_COUNT;
return err;
}
......@@ -429,7 +424,6 @@ static int proc_write_status(struct file *file, const char *buffer,
struct binfmt_entry *e;
int res = count;
MOD_INC_USE_COUNT;
if (buffer[count-1] == '\n')
count--;
if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
......@@ -449,7 +443,6 @@ static int proc_write_status(struct file *file, const char *buffer,
} else {
res = -EINVAL;
}
MOD_DEC_USE_COUNT;
return res;
}
......@@ -477,29 +470,57 @@ static int entry_proc_setup(struct binfmt_entry *e)
return 0;
}
#ifdef MODULE
/*
* This is called as the fill_inode function when an inode
* is going into (fill = 1) or out of service (fill = 0).
* We use it here to manage the module use counts.
*
* Note: only the top-level directory needs to do this; if
* a lower level is referenced, the parent will be as well.
*/
static void bm_modcount(struct inode *inode, int fill)
{
if (fill)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
#endif
__initfunc(int init_misc_binfmt(void))
{
struct proc_dir_entry *status = NULL, *reg;
int error = -ENOMEM;
if (!(bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR,
NULL)) ||
!(status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
bm_dir)) ||
!(reg = create_proc_entry("register", S_IFREG | S_IWUSR,
bm_dir))) {
if (status)
remove_proc_entry("status", bm_dir);
if (bm_dir)
remove_proc_entry("sys/fs/binfmt_misc", NULL);
return -ENOMEM;
}
bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR, NULL);
if (!bm_dir)
goto out;
#ifdef MODULE
bm_dir->fill_inode = bm_modcount;
#endif
status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
bm_dir);
if (!status)
goto cleanup_bm;
status->read_proc = proc_read_status;
status->write_proc = proc_write_status;
reg = create_proc_entry("register", S_IFREG | S_IWUSR, bm_dir);
if (!reg)
goto cleanup_status;
reg->write_proc = proc_write_register;
return register_binfmt(&misc_format);
error = register_binfmt(&misc_format);
out:
return error;
cleanup_status:
remove_proc_entry("status", bm_dir);
cleanup_bm:
remove_proc_entry("sys/fs/binfmt_misc", NULL);
goto out;
}
#ifdef MODULE
......
......@@ -61,22 +61,30 @@ static inline void d_free(struct dentry *dentry)
*/
void dput(struct dentry *dentry)
{
if (dentry) {
int count;
if (!dentry)
return;
repeat:
count = dentry->d_count-1;
if (count < 0) {
printk("Negative d_count (%d) for %s/%s\n",
count,
dentry->d_parent->d_name.name,
dentry->d_name.name);
*(int *)0 = 0;
count = dentry->d_count - 1;
if (count != 0)
goto out;
/*
* Note that if d_op->d_delete blocks,
* the dentry could go back in use.
* Each fs will have to watch for this.
*/
if (dentry->d_op && dentry->d_op->d_delete) {
dentry->d_op->d_delete(dentry);
count = dentry->d_count - 1;
if (count != 0)
goto out;
}
dentry->d_count = count;
if (!count) {
list_del(&dentry->d_lru);
if (dentry->d_op && dentry->d_op->d_delete)
dentry->d_op->d_delete(dentry);
if (list_empty(&dentry->d_hash)) {
struct inode *inode = dentry->d_inode;
struct dentry * parent;
......@@ -90,8 +98,17 @@ void dput(struct dentry *dentry)
goto repeat;
}
list_add(&dentry->d_lru, &dentry_unused);
out:
if (count >= 0) {
dentry->d_count = count;
return;
}
}
printk("Negative d_count (%d) for %s/%s\n",
count,
dentry->d_parent->d_name.name,
dentry->d_name.name);
*(int *)0 = 0;
}
/*
......@@ -99,13 +116,14 @@ void dput(struct dentry *dentry)
* possible. If there are other users of the dentry we
* can't invalidate it.
*
* This is currently incorrect. We should try to see if
* we can invalidate any unused children - right now we
* refuse to invalidate way too much.
* We should probably try to see if we can invalidate
* any unused children - right now we refuse to invalidate
* too much. That would require a better child list
* data structure, though.
*/
int d_invalidate(struct dentry * dentry)
{
/* We should do a partial shrink_dcache here */
/* We might want to do a partial shrink_dcache here */
if (dentry->d_count != 1)
return -EBUSY;
......@@ -113,6 +131,27 @@ int d_invalidate(struct dentry * dentry)
return 0;
}
/*
* Throw away a dentry - free the inode, dput the parent.
* This requires that the LRU list has already been
* removed.
*/
static inline void prune_one_dentry(struct dentry * dentry)
{
struct dentry * parent;
list_del(&dentry->d_hash);
if (dentry->d_inode) {
struct inode * inode = dentry->d_inode;
dentry->d_inode = NULL;
iput(inode);
}
parent = dentry->d_parent;
d_free(dentry);
dput(parent);
}
/*
* Shrink the dcache. This is done when we need
* more memory, or simply when we need to unmount
......@@ -131,24 +170,65 @@ void prune_dcache(int count)
INIT_LIST_HEAD(tmp);
dentry = list_entry(tmp, struct dentry, d_lru);
if (!dentry->d_count) {
struct dentry * parent;
list_del(&dentry->d_hash);
if (dentry->d_inode) {
struct inode * inode = dentry->d_inode;
dentry->d_inode = NULL;
iput(inode);
}
parent = dentry->d_parent;
d_free(dentry);
dput(parent);
prune_one_dentry(dentry);
if (!--count)
break;
}
}
}
/*
* Shrink the dcache for the specified super block.
* This allows us to unmount a device without disturbing
* the dcache for the other devices.
*
* This implementation makes just two traversals of the
* unused list. On the first pass we move the selected
* dentries to the most recent end, and on the second
* pass we free them. The second pass must restart after
* each dput(), but since the target dentries are all at
* the end, it's really just a single traversal.
*/
void shrink_dcache_sb(struct super_block * sb)
{
struct list_head *tmp, *next;
struct dentry *dentry;
/*
* Pass one ... move the dentries for the specified
* superblock to the most recent end of the unused list.
*/
next = dentry_unused.next;
while (next != &dentry_unused) {
tmp = next;
next = tmp->next;
dentry = list_entry(tmp, struct dentry, d_lru);
if (dentry->d_sb != sb)
continue;
list_del(tmp);
list_add(tmp, &dentry_unused);
}
/*
* Pass two ... free the dentries for this superblock.
*/
repeat:
next = dentry_unused.next;
while (next != &dentry_unused) {
tmp = next;
next = tmp->next;
dentry = list_entry(tmp, struct dentry, d_lru);
if (dentry->d_sb != sb)
continue;
if (dentry->d_count)
continue;
list_del(tmp);
INIT_LIST_HEAD(tmp);
prune_one_dentry(dentry);
goto repeat;
}
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
......
......@@ -18,8 +18,9 @@
static kmem_cache_t *filp_cache;
/* sysctl tunables... */
int nr_files = 0;
int max_files = NR_FILE;
int nr_files = 0; /* read only */
int nr_free_files = 0; /* read only */
int max_files = NR_FILE;/* tunable */
/* Free list management, if you are here you must have f_count == 0 */
static struct file * free_filps = NULL;
......@@ -30,6 +31,7 @@ void insert_file_free(struct file *file)
free_filps->f_pprev = &file->f_next;
free_filps = file;
file->f_pprev = &free_filps;
nr_free_files++;
}
/* The list of in-use filp's must be exported (ugh...) */
......@@ -43,6 +45,7 @@ static inline void put_inuse(struct file *file)
file->f_pprev = &inuse_filps;
}
/* N.B. This should be an __initfunc ... */
void file_table_init(void)
{
filp_cache = kmem_cache_create("filp", sizeof(struct file),
......@@ -50,6 +53,11 @@ void file_table_init(void)
SLAB_HWCACHE_ALIGN, NULL, NULL);
if(!filp_cache)
panic("VFS: Cannot alloc filp SLAB cache.");
/*
* We could allocate the reserved files here, but really
* shouldn't need to: the normal boot process will create
* plenty of free files.
*/
}
/* Find an unused file structure and return a pointer to it.
......@@ -61,24 +69,31 @@ struct file * get_empty_filp(void)
static int old_max = 0;
struct file * f;
if (nr_free_files > NR_RESERVED_FILES) {
used_one:
f = free_filps;
if (!f)
goto get_more;
remove_filp(f);
got_one:
nr_free_files--;
new_one:
memset(f, 0, sizeof(*f));
f->f_count = 1;
f->f_version = ++event;
put_inuse(f);
return f;
get_more:
/* Reserve a few files for the super-user.. */
if (nr_files < (current->euid ? max_files - 10 : max_files)) {
}
/*
* Use a reserved one if we're the superuser
*/
if (nr_free_files && !current->euid)
goto used_one;
/*
* Allocate a new one if we're below the limit.
*/
if (nr_files < max_files) {
f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
if (f) {
nr_files++;
goto got_one;
goto new_one;
}
/* Big problems... */
printk("VFS: filp allocation failed\n");
......
......@@ -160,8 +160,9 @@ static inline int
nlmclnt_grace_wait(struct nlm_host *host)
{
if (!host->h_reclaiming)
current->timeout = 10 * HZ;
current->timeout = jiffies + 10 * HZ;
interruptible_sleep_on(&host->h_gracewait);
current->timeout = 0;
return signalled()? -ERESTARTSYS : 0;
}
......@@ -178,9 +179,11 @@ nlmclnt_alloc_call(void)
sizeof(struct nlm_rqst));
if (call)
return call;
current->timeout = 5 * HZ;
printk("nlmclnt_alloc_call: failed, waiting for memory\n");
current->timeout = jiffies + 5 * HZ;
current->state = TASK_INTERRUPTIBLE;
schedule();
current->timeout = 0;
}
return NULL;
}
......@@ -232,6 +235,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
/* Back off a little and try again */
current->timeout = jiffies + 15 * HZ;
interruptible_sleep_on(&host->h_gracewait);
current->timeout = 0;
} while (!signalled());
return -ERESTARTSYS;
......
......@@ -42,11 +42,15 @@
extern struct svc_program nlmsvc_program;
struct nlmsvc_binding * nlmsvc_ops = NULL;
static int nlmsvc_sema = 0;
static int nlmsvc_pid = 0;
static struct semaphore nlmsvc_sema = MUTEX;
static unsigned int nlmsvc_users = 0;
static pid_t nlmsvc_pid = 0;
unsigned long nlmsvc_grace_period = 0;
unsigned long nlmsvc_timeout = 0;
static struct wait_queue * lockd_start = NULL;
static struct wait_queue * lockd_exit = NULL;
/*
* Currently the following can be set only at insmod time.
* Ideally, they would be accessible through the sysctl interface.
......@@ -64,10 +68,16 @@ lockd(struct svc_rqst *rqstp)
sigset_t oldsigmask;
int err = 0;
lock_kernel();
/* Lock module and set up kernel thread */
MOD_INC_USE_COUNT;
/* exit_files(current); */
lock_kernel();
/*
* Let our maker know we're running.
*/
nlmsvc_pid = current->pid;
wake_up(&lockd_start);
exit_mm(current);
current->session = 1;
current->pgrp = 1;
......@@ -76,6 +86,12 @@ lockd(struct svc_rqst *rqstp)
/* kick rpciod */
rpciod_up();
/*
* N.B. current do_fork() doesn't like NULL task->files,
* so we defer closing files until forking rpciod.
*/
exit_files(current);
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
if (!nlm_timeout)
......@@ -94,14 +110,14 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_grace_period += jiffies;
nlmsvc_timeout = nlm_timeout * HZ;
nlmsvc_pid = current->pid;
/*
* The main request loop. We don't terminate until the last
* NFS mount or NFS daemon has gone away, and we've been sent a
* signal.
* signal, or else another process has taken over our job.
*/
while (nlmsvc_sema || !signalled()) {
while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
{
if (signalled())
current->signal = 0;
......@@ -156,7 +172,16 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_ops->exp_unlock();
}
/*
* Check whether there's a new lockd process before
* shutting down the hosts and clearing the slot.
*/
if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
nlm_shutdown_hosts();
nlmsvc_pid = 0;
} else
printk("lockd: new process, skipping host shutdown\n");
wake_up(&lockd_exit);
/* Exit the RPC thread */
svc_exit_thread(rqstp);
......@@ -166,7 +191,6 @@ lockd(struct svc_rqst *rqstp)
/* Release module */
MOD_DEC_USE_COUNT;
nlmsvc_pid = 0;
}
/*
......@@ -185,42 +209,100 @@ lockd_makesock(struct svc_serv *serv, int protocol, unsigned short port)
return svc_create_socket(serv, protocol, &sin);
}
/*
* Bring up the lockd process if it's not already up.
*/
int
lockd_up(void)
{
struct svc_serv * serv;
int error;
int error = 0;
if (nlmsvc_pid || nlmsvc_sema++)
return 0;
down(&nlmsvc_sema);
/*
* Unconditionally increment the user count ... this is
* the number of clients who _want_ a lockd process.
*/
nlmsvc_users++;
/*
* Check whether we're already up and running.
*/
if (nlmsvc_pid)
goto out;
dprintk("lockd: creating service\n");
if ((serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE)) == NULL)
return -ENOMEM;
/*
* Sanity check: if there's no pid,
* we should be the first user ...
*/
if (nlmsvc_users > 1)
printk("lockd_up: no pid, %d users??\n", nlmsvc_users);
error = -ENOMEM;
serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE);
if (!serv) {
printk("lockd_up: create service failed\n");
goto out;
}
if ((error = lockd_makesock(serv, IPPROTO_UDP, 0)) < 0
|| (error = lockd_makesock(serv, IPPROTO_TCP, 0)) < 0) {
svc_destroy(serv);
return error;
printk("lockd_up: makesock failed, error=%d\n", error);
goto destroy_and_out;
}
if ((error = svc_create_thread(lockd, serv)) < 0)
nlmsvc_sema--;
/*
* Create the kernel thread and wait for it to start.
*/
error = svc_create_thread(lockd, serv);
if (error) {
printk("lockd_up: create thread failed, error=%d\n", error);
goto destroy_and_out;
}
sleep_on(&lockd_start);
/* Release server */
/*
* Note: svc_serv structures have an initial use count of 1,
* so we exit through here on both success and failure.
*/
destroy_and_out:
svc_destroy(serv);
return 0;
out:
up(&nlmsvc_sema);
return error;
}
/*
* Decrement the user count and bring down lockd if we're the last.
*/
void
lockd_down(void)
{
if (!nlmsvc_pid || --nlmsvc_sema > 0)
return;
down(&nlmsvc_sema);
if (nlmsvc_users) {
if (--nlmsvc_users)
goto out;
} else
printk("lockd_down: no users! pid=%d\n", nlmsvc_pid);
if (!nlmsvc_pid) {
printk("lockd_down: nothing to do!\n");
goto out;
}
kill_proc(nlmsvc_pid, SIGKILL, 1);
nlmsvc_sema = 0;
/*
* Wait for the lockd process to exit, but since we're holding
* the lockd semaphore, we can't wait around forever ...
*/
current->timeout = jiffies + 5 * HZ;
interruptible_sleep_on(&lockd_exit);
current->timeout = 0;
if (nlmsvc_pid) {
printk("lockd_down: lockd failed to exit, clearing pid\n");
nlmsvc_pid = 0;
}
out:
up(&nlmsvc_sema);
}
#ifdef MODULE
......@@ -235,6 +317,11 @@ lockd_down(void)
int
init_module(void)
{
/* Init the static variables */
nlmsvc_sema = MUTEX;
nlmsvc_users = 0;
nlmsvc_pid = 0;
lockd_exit = NULL;
nlmxdr_init();
return 0;
}
......
......@@ -881,9 +881,6 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
if (caller->fl_type != F_UNLCK) {
repeat:
error = -ERESTARTSYS;
if (signal_pending(current))
goto out;
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
......@@ -895,6 +892,9 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
error = -EDEADLK;
if (posix_locks_deadlock(caller, fl))
goto out;
error = -ERESTARTSYS;
if (signal_pending(current))
goto out;
locks_insert_block(fl, caller);
interruptible_sleep_on(&caller->fl_wait);
locks_delete_block(fl, caller);
......
......@@ -232,12 +232,15 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
result = d_lookup(parent, name);
if (!result) {
struct dentry * dentry = d_alloc(parent, name);
result = ERR_PTR(-ENOMEM);
if (dentry) {
int error = dir->i_op->lookup(dir, dentry);
result = ERR_PTR(error);
if (!error)
result = dget(dentry->d_mounts);
dput(dentry);
}
}
up(&dir->i_sem);
return result;
}
......@@ -1170,7 +1173,8 @@ static inline int do_rename(const char * oldname, const char * newname)
if (new_dir->d_inode->i_sb && new_dir->d_inode->i_sb->dq_op)
new_dir->d_inode->i_sb->dq_op->initialize(new_dir->d_inode, -1);
error = old_dir->d_inode->i_op->rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry);
error = old_dir->d_inode->i_op->rename(old_dir->d_inode, old_dentry,
new_dir->d_inode, new_dentry);
exit_lock:
double_unlock(new_dir, old_dir);
......
This diff is collapsed.
......@@ -34,6 +34,8 @@
#define NFSDBG_FACILITY NFSDBG_VFS
extern void nfs_invalidate_dircache_sb(struct super_block *);
static int nfs_notify_change(struct inode *, struct iattr *);
static void nfs_put_inode(struct inode *);
static void nfs_delete_inode(struct inode *);
......@@ -67,6 +69,7 @@ nfs_read_inode(struct inode * inode)
{
inode->i_blksize = inode->i_sb->s_blocksize;
inode->i_mode = 0;
inode->i_rdev = 0;
inode->i_op = NULL;
NFS_CACHEINV(inode);
}
......@@ -75,6 +78,11 @@ static void
nfs_put_inode(struct inode * inode)
{
dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
/*
* We want to get rid of unused inodes ...
*/
if (inode->i_count == 1)
inode->i_nlink = 0;
}
static void
......@@ -90,13 +98,21 @@ nfs_put_super(struct super_block *sb)
struct nfs_server *server = &sb->u.nfs_sb.s_server;
struct rpc_clnt *rpc;
/*
* Lock the super block while we bring down the daemons.
*/
lock_super(sb);
if ((rpc = server->client) != NULL)
rpc_shutdown_client(rpc);
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_down(); /* release rpc.lockd */
rpciod_down(); /* release rpciod */
lock_super(sb);
/*
* Invalidate the dircache for this superblock.
*/
nfs_invalidate_dircache_sb(sb);
sb->s_dev = 0;
unlock_super(sb);
MOD_DEC_USE_COUNT;
......@@ -147,14 +163,12 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
unsigned int authflavor;
int tcp;
kdev_t dev = sb->s_dev;
struct inode *root_inode;
MOD_INC_USE_COUNT;
if (!data) {
printk("nfs_read_super: missing data argument\n");
sb->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
if (!data)
goto out_miss_args;
if (data->version != NFS_MOUNT_VERSION) {
printk("nfs warning: mount version %s than kernel\n",
data->version < NFS_MOUNT_VERSION ? "older" : "newer");
......@@ -164,13 +178,19 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
data->bsize = 0;
}
/* We now require that the mount process passes the remote address */
memcpy(&srvaddr, &data->addr, sizeof(srvaddr));
if (srvaddr.sin_addr.s_addr == INADDR_ANY)
goto out_no_remote;
lock_super(sb);
server = &sb->u.nfs_sb.s_server;
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_dev = dev;
sb->s_op = &nfs_sops;
sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
sb->u.nfs_sb.s_root = data->root;
server = &sb->u.nfs_sb.s_server;
server->rsize = nfs_block_size(data->rsize, NULL);
server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags;
......@@ -179,15 +199,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
strcpy(server->hostname, data->hostname);
sb->u.nfs_sb.s_root = data->root;
/* We now require that the mount process passes the remote address */
memcpy(&srvaddr, &data->addr, sizeof(srvaddr));
if (srvaddr.sin_addr.s_addr == INADDR_ANY) {
printk("NFS: mount program didn't pass remote address!\n");
MOD_DEC_USE_COUNT;
return NULL;
}
/* Which protocol do we use? */
tcp = (data->flags & NFS_MOUNT_TCP);
......@@ -210,18 +221,13 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
/* Now create transport and client */
xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
&srvaddr, &timeparms);
if (xprt == NULL) {
printk("NFS: cannot create RPC transport.\n");
goto failure;
}
if (xprt == NULL)
goto out_no_xprt;
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
NFS_VERSION, authflavor);
if (clnt == NULL) {
printk("NFS: cannot create RPC client.\n");
xprt_destroy(xprt);
goto failure;
}
if (clnt == NULL)
goto out_no_client;
clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
......@@ -229,29 +235,67 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server->client = clnt;
/* Fire up rpciod if not yet running */
#ifdef RPCIOD_RESULT
if (rpciod_up())
goto out_no_iod;
#else
rpciod_up();
#endif
/* Unlock super block and try to get root fh attributes */
/*
* Keep the super block locked while we try to get
* the root fh attributes.
*/
root_inode = nfs_fhget(sb, &data->root, NULL);
if (!root_inode)
goto out_no_root;
sb->s_root = d_alloc_root(root_inode, NULL);
if (!sb->s_root)
goto out_no_root;
/* We're airborne */
unlock_super(sb);
sb->s_root = d_alloc_root(nfs_fhget(sb, &data->root, NULL), NULL);
if (sb->s_root != NULL) {
/* We're airborne */
/* Check whether to start the lockd process */
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_up();
return sb;
}
/* Yargs. It didn't work out. */
out_no_root:
printk("nfs_read_super: get root inode failed\n");
rpc_shutdown_client(server->client);
iput(root_inode);
rpciod_down();
#ifdef RPCIOD_RESULT
goto out_shutdown;
failure:
MOD_DEC_USE_COUNT;
if (sb->s_lock)
out_no_iod:
printk("nfs_read_super: couldn't start rpciod!\n");
out_shutdown:
#endif
rpc_shutdown_client(server->client);
goto out_unlock;
out_no_client:
printk("NFS: cannot create RPC client.\n");
xprt_destroy(xprt);
goto out_unlock;
out_no_xprt:
printk("NFS: cannot create RPC transport.\n");
out_unlock:
unlock_super(sb);
goto out_fail;
out_no_remote:
printk("NFS: mount program didn't pass remote address!\n");
goto out_fail;
out_miss_args:
printk("nfs_read_super: missing data argument\n");
out_fail:
sb->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
......
......@@ -23,6 +23,7 @@
#include <linux/nfs_fs.h>
#define NFSDBG_FACILITY NFSDBG_XDR
/* #define NFS_PARANOIA 1 */
#define QUADLEN(len) (((len) + 3) >> 2)
static int nfs_stat_to_errno(int stat);
......@@ -371,17 +372,18 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
* to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
* After decoding, the layout in memory looks like this:
* entry1 entry2 ... entryN <space> stringN ... string2 string1
* Each entry consists of three __u32 values, the same space as NFS uses.
* Note that the strings are not null-terminated so that the entire number
* of entries returned by the server should fit into the buffer.
*/
static int
nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
{
struct nfs_entry *entry;
struct iovec *iov = req->rq_rvec;
int status, nr, len;
char *string;
char *string, *start;
u32 *end;
__u32 fileid, cookie, *entry;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
......@@ -396,10 +398,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
end = (u32 *) ((u8 *) p + iov[1].iov_len);
/* Get start and end of dirent buffer */
entry = (struct nfs_entry *) res->buffer;
entry = (__u32 *) res->buffer;
start = (char *) res->buffer;
string = (char *) res->buffer + res->bufsiz;
for (nr = 0; *p++; nr++, entry++) {
entry->fileid = ntohl(*p++);
for (nr = 0; *p++; nr++) {
fileid = ntohl(*p++);
len = ntohl(*p++);
if ((p + QUADLEN(len) + 3) > end) {
......@@ -413,27 +416,36 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return -errno_NFSERR_IO;
}
string -= len;
if ((void *) (entry+1) > (void *) string) {
/* This may actually happen because an nfs_entry
* will take up more space than the XDR data. On
* 32bit machines that's due to 8byte alignment,
* on 64bit machines that's because the char * takes
* up 2 longs.
*
* THIS IS BAD!
if ((void *) (entry+3) > (void *) string) {
/*
* This error is impossible as long as the temp
* buffer is no larger than the user buffer. The
* current packing algorithm uses the same amount
* of space in the user buffer as in the XDR data,
* so it's guaranteed to fit.
*/
printk(KERN_NOTICE "NFS: should not happen in %s!\n",
printk("NFS: incorrect buffer size in %s!\n",
__FUNCTION__);
break;
}
entry->name = string;
entry->length = len;
memmove(string, p, len);
p += QUADLEN(len);
entry->cookie = ntohl(*p++);
entry->eof = !p[0] && p[1];
cookie = ntohl(*p++);
/*
* To make everything fit, we encode the length, offset,
* and eof flag into 32 bits. This works for filenames
* up to 32K and PAGE_SIZE up to 64K.
*/
status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
*entry++ = fileid;
*entry++ = cookie;
*entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
}
#ifdef NFS_PARANOIA
printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
nr, ((char *) entry - start), (start + res->bufsiz - string));
#endif
return nr;
}
......
......@@ -384,17 +384,18 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
* to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
* After decoding, the layout in memory looks like this:
* entry1 entry2 ... entryN <space> stringN ... string2 string1
* Each entry consists of three __u32 values, the same space as NFS uses.
* Note that the strings are not null-terminated so that the entire number
* of entries returned by the server should fit into the buffer.
*/
static int
nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
{
struct nfs_entry *entry;
struct iovec *iov = req->rq_rvec;
int status, nr, len;
char *string;
char *string, *start;
u32 *end;
__u32 fileid, cookie, *entry;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
......@@ -413,10 +414,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return -errno_NFSERR_IO;
}
string = (char *) res->buffer + res->bufsiz;
entry = (struct nfs_entry *) res->buffer;
for (nr = 0; *p++; nr++, entry++) {
entry->fileid = ntohl(*p++);
entry = (__u32 *) res->buffer;
start = (char *) res->buffer;
string = start + res->bufsiz;
for (nr = 0; *p++; nr++) {
fileid = ntohl(*p++);
len = ntohl(*p++);
if ((p + QUADLEN(len) + 3) > end) {
......@@ -430,22 +432,40 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return -errno_NFSERR_IO;
}
string -= len;
if ((void *) (entry+1) > (void *) string) {
dprintk("NFS: shouldnothappen in readdirres_decode!\n");
break; /* should not happen */
if ((void *) (entry+3) > (void *) string) {
/*
* This error is impossible as long as the temp
* buffer is no larger than the user buffer. The
* current packing algorithm uses the same amount
* of space in the user buffer as in the XDR data,
* so it's guaranteed to fit.
*/
printk("NFS: incorrect buffer size in %s!\n",
__FUNCTION__);
break;
}
entry->name = string;
entry->length = len;
memmove(string, p, len);
p += QUADLEN(len);
entry->cookie = ntohl(*p++);
entry->eof = !p[0] && p[1];
cookie = ntohl(*p++);
/*
* To make everything fit, we encode the length, offset,
* and eof flag into 32 bits. This works for filenames
* up to 32K and PAGE_SIZE up to 64K.
*/
status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
*entry++ = fileid;
*entry++ = cookie;
*entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
/*
dprintk("NFS: decoded dirent %.*s cookie %d eof %d\n",
len, string, entry->cookie, entry->eof);
len, string, cookie, status);
*/
}
#ifdef NFS_PARANOIA
printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
nr, ((char *) entry - start), (start + res->bufsiz - string));
#endif
return nr;
}
......
......@@ -250,25 +250,43 @@ nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
*/
int
nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
u32 cookie, unsigned int size, struct nfs_entry *entry)
u32 cookie, unsigned int size, __u32 *entry)
{
struct nfs_readdirargs arg;
struct nfs_readdirres res;
void * buffer;
unsigned int buf_size = PAGE_SIZE;
int status;
/* First get a temp buffer for the readdir reply */
while (!(buffer = (void *) get_free_page(GFP_USER))) {
need_resched = 1;
schedule();
if (signalled())
return -ERESTARTSYS;
}
/* N.B. does this really need to be cleared? */
status = -ENOMEM;
buffer = (void *) get_free_page(GFP_KERNEL);
if (!buffer)
goto out;
/*
* Calculate the effective size the buffer. To make sure
* that the returned data will fit into the user's buffer,
* we decrease the buffer size as necessary.
*
* Note: NFS returns three __u32 values for each entry,
* and we assume that the data is packed into the user
* buffer with the same efficiency.
*/
if (size < buf_size)
buf_size = size;
if (server->rsize < buf_size)
buf_size = server->rsize;
#if 0
printk("nfs_proc_readdir: user size=%d, rsize=%d, buf_size=%d\n",
size, server->rsize, buf_size);
#endif
arg.fh = fhandle;
arg.cookie = cookie;
arg.buffer = buffer;
arg.bufsiz = server->rsize < PAGE_SIZE? server->rsize : PAGE_SIZE;
arg.bufsiz = buf_size;
res.buffer = entry;
res.bufsiz = size;
......@@ -276,6 +294,7 @@ nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
status = rpc_call(server->client, NFSPROC_READDIR, &arg, &res, 0);
dprintk("NFS reply readdir: %d\n", status);
free_page((unsigned long) buffer);
out:
return status;
}
......
......@@ -348,6 +348,12 @@ static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
if (!p || !p->mm || ptr >= TASK_SIZE)
return 0;
/* Check for NULL pgd .. shouldn't happen! */
if (!p->mm->pgd) {
printk("get_phys_addr: pid %d has NULL pgd!\n", p->pid);
return 0;
}
page_dir = pgd_offset(p->mm,ptr);
if (pgd_none(*page_dir))
return 0;
......@@ -917,24 +923,34 @@ static int get_statm(int pid, char * buffer)
#define MAPS_LINE_MAX MAPS_LINE_MAX8
static long read_maps (int pid, struct file * file,
char * buf, unsigned long count)
static long read_maps (int pid, struct file * file, char * buf,
unsigned long count)
{
struct task_struct *p = find_task_by_pid(pid);
char * destptr;
struct task_struct *p;
struct vm_area_struct * map, * next;
char * destptr = buf, * buffer;
loff_t lineno;
int column;
struct vm_area_struct * map;
int i;
char * buffer;
int column, i, volatile_task;
long retval;
/*
* We might sleep getting the page, so get it first.
*/
retval = -ENOMEM;
buffer = (char*)__get_free_page(GFP_KERNEL);
if (!buffer)
goto out;
retval = -EINVAL;
p = find_task_by_pid(pid);
if (!p)
return -EINVAL;
goto freepage_out;
if (!p->mm || p->mm == &init_mm || count == 0)
return 0;
goto getlen_out;
buffer = (char*)__get_free_page(GFP_KERNEL);
/* Check whether the mmaps could change if we sleep */
volatile_task = (p != current || p->mm->count > 1);
/* decode f_pos */
lineno = file->f_pos >> MAPS_LINE_SHIFT;
......@@ -944,9 +960,7 @@ static long read_maps (int pid, struct file * file,
for (map = p->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
continue;
destptr = buf;
for ( ; map ; ) {
for ( ; map ; map = next ) {
/* produce the next line */
char *line;
char str[5], *cp = str;
......@@ -957,6 +971,10 @@ static long read_maps (int pid, struct file * file,
MAPS_LINE_MAX4 : MAPS_LINE_MAX8;
int len;
/*
* Get the next vma now (but it won't be used if we sleep).
*/
next = map->vm_next;
flags = map->vm_flags;
*cp++ = flags & VM_READ ? 'r' : '-';
......@@ -993,20 +1011,19 @@ static long read_maps (int pid, struct file * file,
if (column >= len) {
column = 0; /* continue with next line at column 0 */
lineno++;
map = map->vm_next;
continue;
continue; /* we haven't slept */
}
i = len-column;
if (i > count)
i = count;
copy_to_user(destptr, line+column, i);
destptr += i; count -= i;
copy_to_user(destptr, line+column, i); /* may have slept */
destptr += i;
count -= i;
column += i;
if (column >= len) {
column = 0; /* next time: next line at column 0 */
lineno++;
map = map->vm_next;
}
/* done? */
......@@ -1016,15 +1033,20 @@ static long read_maps (int pid, struct file * file,
/* By writing to user space, we might have slept.
* Stop the loop, to avoid a race condition.
*/
if (p != current)
if (volatile_task)
break;
}
/* encode f_pos */
file->f_pos = (lineno << MAPS_LINE_SHIFT) + column;
getlen_out:
retval = destptr - buf;
freepage_out:
free_page((unsigned long)buffer);
return destptr-buf;
out:
return retval;
}
#ifdef CONFIG_MODULES
......
......@@ -50,13 +50,17 @@ static struct inode_operations proc_base_inode_operations = {
NULL /* permission */
};
static void proc_pid_fill_inode(struct inode * inode)
/*
* The fill argument is non-zero when the inode is being filled ...
* we don't need to do anything when it's being deleted.
*/
static void proc_pid_fill_inode(struct inode * inode, int fill)
{
struct task_struct *p;
int pid = inode->i_ino >> 16;
int ino = inode->i_ino & 0xffff;
if ((p = find_task_by_pid(pid)) != NULL) {
if (fill && (p = find_task_by_pid(pid)) != NULL) {
if (p->dumpable || ino == PROC_PID_INO) {
inode->i_uid = p->euid;
inode->i_gid = p->gid;
......
......@@ -16,11 +16,13 @@
#include <linux/stat.h>
#include <asm/bitops.h>
extern struct inode_operations proc_dyna_dir_inode_operations;
static long proc_file_read(struct inode * inode, struct file * file,
char * buf, unsigned long nbytes);
static long proc_file_write(struct inode * inode, struct file * file,
const char * buffer, unsigned long count);
static long long proc_file_lseek(struct file * file, long long offset, int orig);
static long long proc_file_lseek(struct file *, long long, int);
int proc_match(int len, const char *name,struct proc_dir_entry * de)
{
......@@ -44,9 +46,6 @@ static struct file_operations proc_file_operations = {
NULL /* can't fsync */
};
/*
* proc files can do almost nothing..
*/
struct inode_operations proc_file_inode_operations = {
&proc_file_operations, /* default proc file-ops */
NULL, /* create */
......@@ -240,57 +239,77 @@ static int xlate_proc_name(const char *name,
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent)
{
struct proc_dir_entry *ent;
const char *fn;
struct proc_dir_entry *ent = NULL;
const char *fn = name;
int len;
if (parent)
fn = name;
else {
if (xlate_proc_name(name, &parent, &fn))
return NULL;
}
if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
goto out;
len = strlen(fn);
ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
if (!ent)
return NULL;
goto out;
memset(ent, 0, sizeof(struct proc_dir_entry));
memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
ent->name = ((char *) ent) + sizeof(*ent);
ent->namelen = len;
if (mode == S_IFDIR)
if (mode == S_IFDIR) {
mode |= S_IRUGO | S_IXUGO;
else if (mode == 0)
mode = S_IFREG | S_IRUGO;
ent->name = fn;
ent->namelen = strlen(fn);
ent->mode = mode;
if (S_ISDIR(mode))
ent->ops = &proc_dyna_dir_inode_operations;
ent->nlink = 2;
else
}
else if (mode == 0) {
mode = S_IFREG | S_IRUGO;
ent->nlink = 1;
}
ent->mode = mode;
proc_register(parent, ent);
out:
return ent;
}
extern void free_proc_entry(struct proc_dir_entry *);
void free_proc_entry(struct proc_dir_entry *de)
{
kfree(de);
}
/*
* Remove a /proc entry and free it if it's not currently in use.
* If it is in use, we set the 'deleted' flag.
*/
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
{
struct proc_dir_entry *de;
const char *fn;
const char *fn = name;
int len;
if (parent)
fn = name;
else
if (xlate_proc_name(name, &parent, &fn))
return;
if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
goto out;
len = strlen(fn);
for (de = parent->subdir; de ; de = de->next) {
if (proc_match(len, fn, de))
break;
}
if (de)
if (de) {
printk("remove_proc_entry: parent nlink=%d, file nlink=%d\n",
parent->nlink, de->nlink);
proc_unregister(parent, de->low_ino);
kfree(de);
de->nlink = 0;
de->deleted = 1;
if (!de->count)
free_proc_entry(de);
else {
printk("remove_proc_entry: %s/%s busy, count=%d\n",
parent->name, de->name, de->count);
}
}
out:
return;
}
......@@ -17,23 +17,66 @@
#include <asm/system.h>
#include <asm/uaccess.h>
extern void free_proc_entry(struct proc_dir_entry *);
struct proc_dir_entry * de_get(struct proc_dir_entry *de)
{
if (de)
de->count++;
return de;
}
/*
* Decrements the use count and checks for deferred deletion.
*/
void de_put(struct proc_dir_entry *de)
{
if (de) {
if (!de->count) {
printk("de_put: entry %s already free!\n", de->name);
return;
}
if (!--de->count) {
if (de->deleted) {
printk("de_put: deferred delete of %s\n",
de->name);
free_proc_entry(de);
}
}
}
}
static void proc_put_inode(struct inode *inode)
{
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
if ((inode->i_ino >= PROC_OPENPROM_FIRST)
&& (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
&& proc_openprom_use)
if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
(inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM) &&
proc_openprom_use)
(*proc_openprom_use)(inode, 0);
#endif
/*
* Kill off unused inodes ... VFS will unhash and
* delete the inode if we set i_nlink to zero.
*/
if (inode->i_count == 1)
inode->i_nlink = 0;
}
/*
* Does this ever happen?
* Decrement the use count of the proc_dir_entry.
*/
static void proc_delete_inode(struct inode *inode)
{
printk("proc_delete_inode()?\n");
inode->i_size = 0;
struct proc_dir_entry *de = inode->u.generic_ip;
if (de) {
/*
* Call the fill_inode hook to release module counts.
*/
if (de->fill_inode)
de->fill_inode(inode, 0);
de_put(de);
}
}
static void proc_put_super(struct super_block *sb)
......@@ -47,7 +90,7 @@ static struct super_operations proc_sops = {
proc_read_inode,
proc_write_inode,
proc_put_inode,
proc_delete_inode,
proc_delete_inode, /* delete_inode(struct inode *) */
NULL,
proc_put_super,
NULL,
......@@ -85,9 +128,24 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
return 1;
}
struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
struct inode * proc_get_inode(struct super_block * sb, int ino,
struct proc_dir_entry * de)
{
struct inode * inode = iget(s, ino);
struct inode * inode;
/*
* Increment the use count so the dir entry can't disappear.
*/
de_get(de);
#if 1
/* shouldn't ever happen */
if (de && de->deleted)
printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
#endif
inode = iget(sb, ino);
if (!inode)
goto out_fail;
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
if ((inode->i_ino >= PROC_OPENPROM_FIRST)
......@@ -95,7 +153,10 @@ struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_e
&& proc_openprom_use)
(*proc_openprom_use)(inode, 1);
#endif
if (inode && inode->i_sb == s) {
/* N.B. How can this test ever fail?? */
if (inode->i_sb != sb)
printk("proc_get_inode: inode fubar\n");
inode->u.generic_ip = (void *) de;
if (de) {
if (de->mode) {
......@@ -109,9 +170,12 @@ struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_e
inode->i_op = de->ops;
if (de->nlink)
inode->i_nlink = de->nlink;
/*
* The fill_inode routine should use this call
* to increment module counts, if necessary.
*/
if (de->fill_inode)
de->fill_inode(inode);
}
de->fill_inode(inode, 1);
}
/*
* Fixup the root inode's nlink value
......@@ -126,26 +190,40 @@ struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_e
}
read_unlock(&tasklist_lock);
}
out:
return inode;
out_fail:
de_put(de);
goto out;
}
struct super_block *proc_read_super(struct super_block *s,void *data,
int silent)
{
struct inode * root_inode;
lock_super(s);
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = PROC_SUPER_MAGIC;
s->s_op = &proc_sops;
root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
if (!root_inode)
goto out_no_root;
s->s_root = d_alloc_root(root_inode, NULL);
if (!s->s_root)
goto out_no_root;
parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
unlock_super(s);
s->s_root = d_alloc_root(proc_get_inode(s, PROC_ROOT_INO, &proc_root), NULL);
if (!s->s_root) {
return s;
out_no_root:
printk("proc_read_super: get root inode failed\n");
iput(root_inode);
s->s_dev = 0;
printk("get root inode failed\n");
unlock_super(s);
return NULL;
}
parse_options(data, &s->s_root->d_inode->i_uid, &s->s_root->d_inode->i_gid);
return s;
}
int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
......
......@@ -25,6 +25,7 @@
static int proc_root_readdir(struct file *, void *, filldir_t);
static int proc_root_lookup(struct inode *,struct dentry *);
static int proc_unlink(struct inode *, struct dentry *);
static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
......@@ -72,6 +73,29 @@ struct inode_operations proc_dir_inode_operations = {
NULL /* permission */
};
/*
* /proc dynamic directories now support unlinking
*/
struct inode_operations proc_dyna_dir_inode_operations = {
&proc_dir_operations, /* default proc dir ops */
NULL, /* create */
proc_lookup, /* lookup */
NULL, /* link */
proc_unlink, /* unlink(struct inode *, struct dentry *) */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/*
* The root /proc directory is special, as it has the
* <pid> directories. Thus we don't use the generic
......@@ -173,7 +197,8 @@ proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, fil
int proc_openprom_regdev(struct openpromfs_dev *d)
{
if (proc_openpromdev_ino == PROC_OPENPROMD_FIRST + PROC_NOPENPROMD) return -1;
if (proc_openpromdev_ino == PROC_OPENPROMD_FIRST + PROC_NOPENPROMD)
return -1;
d->next = proc_openprom_devices;
d->inode = proc_openpromdev_ino++;
proc_openprom_devices = d;
......@@ -218,6 +243,7 @@ proc_openprom_defreaddir(struct inode * inode, struct file * filp,
(inode, filp, dirent, filldir);
return -EINVAL;
}
#define OPENPROM_DEFREADDIR proc_openprom_defreaddir
static int
proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
......@@ -229,17 +255,17 @@ proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
(dir, dentry);
return -ENOENT;
}
#define OPENPROM_DEFLOOKUP proc_openprom_deflookup
#else
#define OPENPROM_DEFREADDIR NULL
#define OPENPROM_DEFLOOKUP NULL
#endif
static struct file_operations proc_openprom_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KERNELD)
proc_openprom_defreaddir,/* readdir */
#else
NULL, /* readdir */
#endif
OPENPROM_DEFREADDIR, /* readdir */
NULL, /* poll - default */
NULL, /* ioctl - default */
NULL, /* mmap */
......@@ -251,11 +277,7 @@ static struct file_operations proc_openprom_operations = {
struct inode_operations proc_openprom_inode_operations = {
&proc_openprom_operations,/* default net directory file-ops */
NULL, /* create */
#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KERNELD)
proc_openprom_deflookup,/* lookup */
#else
NULL, /* lookup */
#endif
OPENPROM_DEFLOOKUP, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
......@@ -638,6 +660,26 @@ void proc_root_init(void)
#endif
}
/*
* As some entries in /proc are volatile, we want to
* get rid of unused dentries. This could be made
* smarter: we could keep a "volatile" flag in the
* inode to indicate which ones to keep.
*/
static void
proc_delete_dentry(struct dentry * dentry)
{
d_drop(dentry);
}
static struct dentry_operations proc_dentry_operations =
{
NULL, /* revalidate */
NULL, /* d_hash */
NULL, /* d_compare */
proc_delete_dentry /* d_delete(struct dentry *) */
};
/*
* Don't create negative dentries here, return -ENOENT by hand
* instead.
......@@ -646,12 +688,15 @@ int proc_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode *inode;
struct proc_dir_entry * de;
int error;
error = -ENOTDIR;
if (!dir || !S_ISDIR(dir->i_mode))
return -ENOTDIR;
goto out;
de = (struct proc_dir_entry *) dir->u.generic_ip;
error = -ENOENT;
inode = NULL;
de = (struct proc_dir_entry *) dir->u.generic_ip;
if (de) {
for (de = de->subdir; de ; de = de->next) {
if (!de || !de->low_ino)
......@@ -660,18 +705,20 @@ int proc_lookup(struct inode * dir, struct dentry *dentry)
continue;
if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
int ino = de->low_ino | (dir->i_ino & ~(0xffff));
error = -EINVAL;
inode = proc_get_inode(dir->i_sb, ino, de);
if (!inode)
return -EINVAL;
break;
}
}
}
if (!inode)
return -ENOENT;
if (inode) {
dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
return 0;
error = 0;
}
out:
return error;
}
static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
......@@ -721,6 +768,8 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
if (!inode)
return -EINVAL;
}
dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
return 0;
}
......@@ -827,3 +876,15 @@ static int proc_root_readdir(struct file * filp,
read_unlock(&tasklist_lock);
return 0;
}
static int proc_unlink(struct inode *dir, struct dentry *dentry)
{
struct proc_dir_entry * dp = dir->u.generic_ip;
printk("proc_file_unlink: deleting %s/%s\n", dp->name, dentry->d_name.name);
remove_proc_entry(dentry->d_name.name, dp);
dentry->d_inode->i_nlink = 0;
d_delete(dentry);
return 0;
}
......@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := smbfs.o
O_OBJS := proc.o dir.o sock.o inode.o file.o ioctl.o
O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o
M_OBJS := $(O_TARGET)
# If you want debugging output, please uncomment the following line
......
/*
* cache.c
*
* Copyright (C) 1997 by Bill Hawes
*
* Routines to support directory cacheing using the page cache.
* Right now this only works for smbfs, but will be generalized
* for use with other filesystems.
*/
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/dirent.h>
#include <linux/smb_fs.h>
#include <asm/page.h>
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
static inline struct inode *
get_cache_inode(struct cache_head *cachep)
{
return (mem_map + MAP_NR((unsigned long) cachep))->inode;
}
/*
* Get a pointer to the cache_head structure,
* mapped as the page at offset 0. The page is
* kept locked while we're using the cache.
*/
struct cache_head *
smb_get_dircache(struct dentry * dentry)
{
struct inode * inode = dentry->d_inode;
struct cache_head * cachep;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_get_dircache: finding cache for %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#endif
cachep = (struct cache_head *) get_cached_page(inode, 0, 1);
if (!cachep)
goto out;
if (cachep->valid)
{
struct cache_index * index = cachep->index;
struct cache_block * block;
unsigned long offset;
int i;
cachep->valid = 0;
/*
* Here we only want to find existing cache blocks,
* not add new ones.
*/
for (i = 0; i < cachep->pages; i++, index++) {
#ifdef SMBFS_PARANOIA
if (index->block)
printk("smb_get_dircache: cache %s/%s has existing block!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#endif
offset = PAGE_SIZE + (i << PAGE_SHIFT);
block = (struct cache_block *) get_cached_page(inode,
offset, 0);
if (!block)
goto out;
index->block = block;
}
cachep->valid = 1;
}
out:
return cachep;
}
/*
* Unlock and release the data blocks.
*/
static void
smb_free_cache_blocks(struct cache_head * cachep)
{
struct cache_index * index = cachep->index;
int i;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_free_cache_blocks: freeing %d blocks\n", cachep->pages);
#endif
for (i = 0; i < cachep->pages; i++, index++)
{
if (index->block)
{
put_cached_page((unsigned long) index->block);
index->block = NULL;
}
}
}
/*
* Unlocks and releases the dircache.
*/
void
smb_free_dircache(struct cache_head * cachep)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_free_dircache: freeing cache\n");
#endif
smb_free_cache_blocks(cachep);
put_cached_page((unsigned long) cachep);
}
/*
* Initializes the dircache. We release any existing data blocks,
* and then clear the cache_head structure.
*/
void
smb_init_dircache(struct cache_head * cachep)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_init_dircache: initializing cache, %d blocks\n", cachep->pages);
#endif
smb_free_cache_blocks(cachep);
memset(cachep, 0, sizeof(struct cache_head));
}
/*
* Add a new entry to the cache. This assumes that the
* entries are coming in order and are added to the end.
*/
void
smb_add_to_cache(struct cache_head * cachep, struct dirent *entry, off_t fpos)
{
struct inode * inode = get_cache_inode(cachep);
struct cache_index * index;
struct cache_block * block;
unsigned long page_off;
unsigned int nent, offset, len = entry->d_reclen;
unsigned int needed = len + sizeof(struct cache_entry);
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_add_to_cache: cache inode %p, status %d, adding %s at %ld\n",
inode, cachep->status, entry->d_name, fpos);
#endif
/*
* Don't do anything if we've had an error ...
*/
if (cachep->status)
goto out;
index = &cachep->index[cachep->idx];
if (!index->block)
goto get_block;
/* space available? */
if (needed < index->space)
{
add_entry:
nent = index->num_entries;
index->num_entries++;
index->space -= needed;
offset = index->space +
index->num_entries * sizeof(struct cache_entry);
block = index->block;
memcpy(&block->cb_data.names[offset], entry->d_name, len);
block->cb_data.table[nent].namelen = len;
block->cb_data.table[nent].offset = offset;
block->cb_data.table[nent].ino = entry->d_ino;
cachep->entries++;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_add_to_cache: added entry %s, len=%d, pos=%ld, entries=%d\n",
entry->d_name, len, fpos, cachep->entries);
#endif
return;
}
/*
* This block is full ... advance the index.
*/
cachep->idx++;
if (cachep->idx > NINDEX) /* not likely */
goto out_full;
index++;
#ifdef SMBFS_PARANOIA
if (index->block)
printk("smb_add_to_cache: new index already has block!\n");
#endif
/*
* Get the next cache block
*/
get_block:
cachep->pages++;
page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
block = (struct cache_block *) get_cached_page(inode, page_off, 1);
if (block)
{
index->block = block;
index->space = PAGE_SIZE;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_add_to_cache: inode=%p, pages=%d, block at %ld\n",
inode, cachep->pages, page_off);
#endif
goto add_entry;
}
/*
* On failure, just set the return status ...
*/
out_full:
cachep->status = -ENOMEM;
out:
return;
}
int
smb_find_in_cache(struct cache_head * cachep, off_t pos,
struct cache_dirent *entry)
{
struct cache_index * index = cachep->index;
struct cache_block * block;
unsigned int i, nent, offset = 0;
off_t next_pos = 2;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_find_in_cache: cache %p, looking for pos=%ld\n", cachep, pos);
#endif
for (i = 0; i < cachep->pages; i++, index++)
{
if (pos < next_pos)
break;
nent = pos - next_pos;
next_pos += index->num_entries;
if (pos >= next_pos)
continue;
/*
* The entry is in this block. Note: we return
* then name as a reference with _no_ null byte.
*/
block = index->block;
entry->ino = block->cb_data.table[nent].ino;
entry->len = block->cb_data.table[nent].namelen;
offset = block->cb_data.table[nent].offset;
entry->name = &block->cb_data.names[offset];
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_find_in_cache: found %s, len=%d, pos=%ld\n",
entry->name, entry->len, pos);
#endif
break;
}
return offset;
}
int
smb_refill_dircache(struct cache_head * cachep, struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
int result;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_refill_dircache: cache %s/%s, blocks=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, cachep->pages);
#endif
/*
* Fill the cache, starting at position 2.
*/
retry:
inode->u.smbfs_i.cache_valid = 1;
result = smb_proc_readdir(dentry, 2, cachep);
if (result < 0)
{
#ifdef SMBFS_PARANOIA
printk("smb_refill_dircache: readdir failed, result=%d\n", result);
#endif
goto out;
}
/*
* Check whether the cache was invalidated while
* we were doing the scan ...
*/
if (!inode->u.smbfs_i.cache_valid)
{
#ifdef SMBFS_PARANOIA
printk("smb_refill_dircache: cache invalidated, retrying\n");
#endif
goto retry;
}
result = cachep->status;
if (!result)
{
cachep->valid = 1;
}
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_refill_cache: cache %s/%s status=%d, entries=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
cachep->status, cachep->entries);
#endif
out:
return result;
}
void
smb_invalid_dir_cache(struct inode * dir)
{
/*
* Get rid of any unlocked pages, and clear the
* 'valid' flag in case a scan is in progress.
*/
invalidate_inode_pages(dir);
dir->u.smbfs_i.cache_valid = 0;
}
This diff is collapsed.
......@@ -23,17 +23,29 @@
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
extern int smb_get_rsize(struct smb_sb_info *);
extern int smb_get_wsize(struct smb_sb_info *);
static inline int
min(int a, int b)
{
return a < b ? a : b;
}
static inline void
smb_unlock_page(struct page *page)
{
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
}
static int
smb_fsync(struct file *file, struct dentry * dentry)
{
printk("smb_fsync: sync file %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_fsync: sync file %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#endif
return 0;
}
......@@ -43,14 +55,13 @@ smb_fsync(struct file *file, struct dentry * dentry)
static int
smb_readpage_sync(struct inode *inode, struct page *page)
{
unsigned long offset = page->offset;
char *buffer = (char *) page_address(page);
unsigned long offset = page->offset;
struct dentry * dentry = inode->u.smbfs_i.dentry;
int rsize = SMB_SERVER(inode)->opt.max_xmit - (SMB_HEADER_LEN+15);
int result, refresh = 0;
int rsize = smb_get_rsize(SMB_SERVER(inode));
int count = PAGE_SIZE;
int result;
pr_debug("SMB: smb_readpage_sync(%p)\n", page);
clear_bit(PG_error, &page->flags);
result = -EIO;
......@@ -60,24 +71,22 @@ smb_readpage_sync(struct inode *inode, struct page *page)
goto io_error;
}
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, rsize);
#endif
result = smb_open(dentry, O_RDONLY);
if (result < 0)
goto io_error;
/* Should revalidate inode ... */
do {
if (count < rsize)
rsize = count;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_readpage: reading %s/%s, offset=%ld, buffer=%p, size=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, offset, buffer, rsize);
#endif
result = smb_proc_read(inode, offset, rsize, buffer);
if (result < 0)
goto io_error;
refresh = 1;
count -= result;
offset += result;
buffer += result;
......@@ -90,10 +99,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, offset, buffer, rsize);
result = 0;
io_error:
if (refresh)
smb_refresh_inode(inode);
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
smb_unlock_page(page);
return result;
}
......@@ -110,7 +116,7 @@ smb_readpage(struct inode *inode, struct page *page)
set_bit(PG_locked, &page->flags);
atomic_inc(&page->count);
error = smb_readpage_sync(inode, page);
__free_page(page);
free_page(page_address(page));
return error;
}
......@@ -122,24 +128,24 @@ static int
smb_writepage_sync(struct inode *inode, struct page *page,
unsigned long offset, unsigned int count)
{
int wsize = SMB_SERVER(inode)->opt.max_xmit - (SMB_HEADER_LEN+15);
u8 *buffer = (u8 *) page_address(page) + offset;
int wsize = smb_get_wsize(SMB_SERVER(inode));
int result, refresh = 0, written = 0;
u8 *buffer;
pr_debug("SMB: smb_writepage_sync(%x/%ld %d@%ld)\n",
inode->i_dev, inode->i_ino,
count, page->offset + offset);
buffer = (u8 *) page_address(page) + offset;
offset += page->offset;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_writepage_sync: file %s/%s, count=%d@%ld, wsize=%d\n",
((struct dentry *) inode->u.smbfs_i.dentry)->d_parent->d_name.name,
((struct dentry *) inode->u.smbfs_i.dentry)->d_name.name, count, offset, wsize);
#endif
do {
if (count < wsize)
wsize = count;
result = smb_proc_write(inode, offset, wsize, buffer);
if (result < 0) {
if (result < 0)
{
/* Must mark the page invalid after I/O error */
clear_bit(PG_uptodate, &page->flags);
goto io_error;
......@@ -157,11 +163,11 @@ printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
} while (count);
io_error:
#if 0
if (refresh)
smb_refresh_inode(inode);
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
#endif
smb_unlock_page(page);
return written ? written : result;
}
......@@ -181,7 +187,7 @@ smb_writepage(struct inode *inode, struct page *page)
set_bit(PG_locked, &page->flags);
atomic_inc(&page->count);
result = smb_writepage_sync(inode, page, 0, PAGE_SIZE);
__free_page(page);
free_page(page_address(page));
return result;
}
......@@ -189,7 +195,7 @@ static int
smb_updatepage(struct inode *inode, struct page *page, const char *buffer,
unsigned long offset, unsigned int count, int sync)
{
u8 *page_addr;
unsigned long page_addr = page_address(page);
int result;
pr_debug("SMB: smb_updatepage(%x/%ld %d@%ld, sync=%d)\n",
......@@ -203,21 +209,21 @@ smb_updatepage(struct inode *inode, struct page *page, const char *buffer,
set_bit(PG_locked, &page->flags);
atomic_inc(&page->count);
page_addr = (u8 *) page_address(page);
if (copy_from_user(page_addr + offset, buffer, count))
if (copy_from_user((char *) page_addr + offset, buffer, count))
goto bad_fault;
result = smb_writepage_sync(inode, page, offset, count);
out:
__free_page(page);
free_page(page_addr);
return result;
bad_fault:
printk("smb_updatepage: fault at page=%p buffer=%p\n", page, buffer);
#ifdef SMBFS_PARANOIA
printk("smb_updatepage: fault at addr=%lu, offset=%lu, buffer=%p\n",
page_addr, offset, buffer);
#endif
result = -EFAULT;
clear_bit(PG_uptodate, &page->flags);
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
smb_unlock_page(page);
goto out;
}
......@@ -227,9 +233,11 @@ smb_file_read(struct inode * inode, struct file * file,
{
int status;
pr_debug("SMB: read(%x/%ld (%d), %lu@%lu)\n",
inode->i_dev, inode->i_ino, inode->i_count,
count, (unsigned long) file->f_pos);
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_read: file %s/%s, count=%lu@%lu\n",
file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
count, (unsigned long) file->f_pos);
#endif
status = smb_revalidate_inode(inode);
if (status >= 0)
......@@ -246,6 +254,11 @@ smb_file_mmap(struct file * file, struct vm_area_struct * vma)
struct inode * inode = dentry->d_inode;
int status;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_mmap: file %s/%s, address %lu - %lu\n",
file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
vma->vm_start, vma->vm_end);
#endif
status = smb_revalidate_inode(inode);
if (status >= 0)
{
......@@ -263,40 +276,67 @@ smb_file_write(struct inode *inode, struct file *file,
{
int result;
pr_debug("SMB: write(%x/%ld (%d), %lu@%lu)\n",
inode->i_dev, inode->i_ino, inode->i_count,
count, (unsigned long) file->f_pos);
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_write: file %s/%s, count=%lu@%lu\n",
file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
count, (unsigned long) file->f_pos);
#endif
#ifdef SMBFS_PARANOIA
/* Should be impossible now that inodes can't change mode */
result = -EINVAL;
if (!inode) {
printk("smb_file_write: inode = NULL\n");
if (!S_ISREG(inode->i_mode))
{
printk("smb_file_write: write to non-file, mode %07o\n",
inode->i_mode);
goto out;
}
#endif
result = smb_revalidate_inode(inode);
if (result < 0)
if (result)
goto out;
result = smb_open(file->f_dentry, O_WRONLY);
if (result < 0)
if (result)
goto out;
result = -EINVAL;
if (!S_ISREG(inode->i_mode)) {
printk("smb_file_write: write to non-file, mode %07o\n",
inode->i_mode);
goto out;
}
result = 0;
if (count > 0)
{
result = generic_file_write(inode, file, buf, count);
if (result > 0)
smb_refresh_inode(inode);
}
out:
return result;
}
static int
smb_file_open(struct inode *inode, struct file * file)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_open: inode=%p, file=%p\n", inode, file);
#endif
return 0;
}
static int
smb_file_release(struct inode *inode, struct file * file)
{
struct dentry * dentry = file->f_dentry;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_release: closing file %s/%s, d_count=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
#endif
if (dentry->d_count == 1)
{
smb_close(inode);
}
return 0;
}
static struct file_operations smb_file_operations =
{
NULL, /* lseek - default */
......@@ -305,10 +345,14 @@ static struct file_operations smb_file_operations =
NULL, /* readdir - bad */
NULL, /* poll - default */
smb_ioctl, /* ioctl */
smb_file_mmap, /* mmap */
NULL, /* open */
NULL, /* release */
smb_fsync, /* fsync */
smb_file_mmap, /* mmap(struct file*, struct vm_area_struct*) */
smb_file_open, /* open(struct inode*, struct file*) */
smb_file_release, /* release(struct inode*, struct file*) */
smb_fsync, /* fsync(struct file*, struct dentry*) */
NULL, /* fasync(struct file*, int) */
NULL, /* check_media_change(kdev_t dev) */
NULL, /* revalidate(kdev_t dev) */
NULL /* lock(struct file*, int, struct file_lock*) */
};
struct inode_operations smb_file_inode_operations =
......
This diff is collapsed.
This diff is collapsed.
......@@ -126,18 +126,26 @@ smb_data_callback(struct sock *sk, int len)
}
}
int
smb_valid_socket(struct inode * inode)
{
return (inode && S_ISSOCK(inode->i_mode) &&
inode->u.socket_i.type == SOCK_STREAM);
}
static struct socket *
server_sock(struct smb_sb_info *server)
{
struct file *file;
struct inode *inode;
if (server &&
(file = server->sock_file) &&
(inode = file->f_dentry->d_inode) &&
S_ISSOCK(inode->i_mode) &&
inode->u.socket_i.type == SOCK_STREAM)
return &(inode->u.socket_i);
if (server && (file = server->sock_file))
{
#ifdef SMBFS_PARANOIA
if (!smb_valid_socket(file->f_dentry->d_inode))
printk("smb_server_sock: bad socket!\n");
#endif
return &file->f_dentry->d_inode->u.socket_i;
}
return NULL;
}
......@@ -242,15 +250,13 @@ smb_close_socket(struct smb_sb_info *server)
if (file)
{
struct socket * socket = server_sock(server);
printk("smb_close_socket: closing socket %p\n", socket);
/*
* We need a way to check for tasks running the callback!
*/
if (socket->sk->data_ready == smb_data_callback)
printk("smb_close_socket: still catching keepalives!\n");
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_close_socket: closing socket %p\n", server_sock(server));
#endif
#ifdef SMBFS_PARANOIA
if (server_sock(server)->sk->data_ready == smb_data_callback)
printk("smb_close_socket: still catching keepalives!\n");
#endif
server->sock_file = NULL;
close_fp(file);
}
......@@ -325,7 +331,9 @@ smb_get_length(struct socket *socket, unsigned char *header)
if (result < 0)
{
pr_debug("smb_get_length: recv error = %d\n", -result);
#ifdef SMBFS_PARANOIA
printk("smb_get_length: recv error = %d\n", -result);
#endif
return result;
}
switch (peek_buf[0])
......@@ -339,7 +347,9 @@ smb_get_length(struct socket *socket, unsigned char *header)
goto re_recv;
default:
pr_debug("smb_get_length: Invalid NBT packet\n");
#ifdef SMBFS_PARANOIA
printk("smb_get_length: Invalid NBT packet, code=%x\n", peek_buf[0]);
#endif
return -EIO;
}
......@@ -359,39 +369,39 @@ static int
smb_receive(struct smb_sb_info *server)
{
struct socket *socket = server_sock(server);
int len;
int result;
int len, result;
unsigned char peek_buf[4];
len = smb_get_length(socket, peek_buf);
if (len < 0)
{
return len;
}
result = smb_get_length(socket, peek_buf);
if (result < 0)
goto out;
len = result;
/*
* Some servers do not respect our max_xmit and send
* larger packets. Try to allocate a new packet,
* but don't free the old one unless we succeed.
*/
if (len + 4 > server->packet_size)
{
/* Some servers do not care about our max_xmit. They
send larger packets */
char * packet;
pr_debug("smb_receive: Increase packet size from %d to %d\n",
server->packet_size, len + 4);
result = -ENOMEM;
packet = smb_vmalloc(len + 4);
if (packet == NULL)
goto out;
smb_vfree(server->packet);
server->packet = 0;
server->packet_size = 0;
server->packet = smb_vmalloc(len + 4);
if (server->packet == NULL)
{
return -ENOMEM;
}
server->packet = packet;
server->packet_size = len + 4;
}
memcpy(server->packet, peek_buf, 4);
result = smb_receive_raw(socket, server->packet + 4, len);
if (result < 0)
{
pr_debug("smb_receive: receive error: %d\n", result);
return result;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_receive: receive error: %d\n", result);
#endif
goto out;
}
server->rcls = *(server->packet+9);
server->err = WVAL(server->packet, 11);
......@@ -400,9 +410,16 @@ smb_receive(struct smb_sb_info *server)
if (server->rcls != 0)
printk("smb_receive: rcls=%d, err=%d\n", server->rcls, server->err);
#endif
out:
return result;
}
/*
* This routine needs a lot of work. We should check whether the packet
* is all one part before allocating a new one, and should try first to
* copy to a temp buffer before allocating.
* The final server->packet should be the larger of the two.
*/
static int
smb_receive_trans2(struct smb_sb_info *server,
int *ldata, unsigned char **data,
......@@ -515,6 +532,11 @@ data_len, total_data, param_len, total_param);
*ldata = data_len;
*lparam = param_len;
#ifdef SMBFS_PARANOIA
if (buf_len < server->packet_size)
printk("smb_receive_trans2: changing packet, old size=%d, new size=%d\n",
server->packet_size, buf_len);
#endif
smb_vfree(server->packet);
server->packet = rcv_buf;
server->packet_size = buf_len;
......@@ -537,9 +559,6 @@ smb_request(struct smb_sb_info *server)
unsigned char *buffer;
result = -EBADF;
if (!server) /* this can't happen */
goto bad_no_server;
buffer = server->packet;
if (!buffer)
goto bad_no_packet;
......@@ -586,13 +605,12 @@ smb_request(struct smb_sb_info *server)
return result;
bad_conn:
printk("smb_request: result %d, setting invalid\n", result);
#ifdef SMBFS_PARANOIA
printk("smb_request: result %d, setting invalid\n", result);
#endif
server->state = CONN_INVALID;
smb_invalidate_inodes(server);
goto out;
bad_no_server:
printk("smb_request: no server!\n");
goto out;
bad_no_packet:
printk("smb_request: no packet!\n");
goto out;
......@@ -631,6 +649,7 @@ smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
struct iovec iov[4];
struct msghdr msg;
/* N.B. This test isn't valid! packet_size may be < max_xmit */
if ((bcc + oparam) > server->opt.max_xmit)
{
return -ENOMEM;
......@@ -639,6 +658,7 @@ smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
WSET(server->packet, smb_tpscnt, lparam);
WSET(server->packet, smb_tdscnt, ldata);
/* N.B. these values should reflect out current packet size */
WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER);
WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER);
WSET(server->packet, smb_msrcnt, 0);
......@@ -745,7 +765,9 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
return result;
bad_conn:
printk("smb_trans2_request: connection bad, setting invalid\n");
#ifdef SMBFS_PARANOIA
printk("smb_trans2_request: connection bad, setting invalid\n");
#endif
server->state = CONN_INVALID;
smb_invalidate_inodes(server);
goto out;
......
......@@ -17,8 +17,6 @@
* Added change_root: Werner Almesberger & Hans Lermen, Feb '96
*/
#include <stdarg.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
......@@ -252,29 +250,24 @@ static int fs_maxindex(void)
/*
* Whee.. Weird sysv syscall.
*/
asmlinkage int sys_sysfs(int option, ...)
asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
{
va_list args;
int retval = -EINVAL;
unsigned int index;
lock_kernel();
va_start(args, option);
switch (option) {
case 1:
retval = fs_index(va_arg(args, const char *));
retval = fs_index((const char *) arg1);
break;
case 2:
index = va_arg(args, unsigned int);
retval = fs_name(index, va_arg(args, char *));
retval = fs_name(arg1, (char *) arg2);
break;
case 3:
retval = fs_maxindex();
break;
}
va_end(args);
unlock_kernel();
return retval;
}
......@@ -933,12 +926,11 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
struct file_system_type * fstype;
struct dentry * dentry = NULL;
struct inode * inode = NULL;
struct file_operations * fops;
kdev_t dev;
int retval = -EPERM;
const char * t;
unsigned long flags = 0;
unsigned long page = 0;
struct file dummy; /* allows read-write or read-only flag */
lock_kernel();
if (!suser())
......@@ -954,6 +946,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
free_page(page);
goto out;
}
retval = copy_mount_options (type, &page);
if (retval < 0)
goto out;
......@@ -962,8 +955,8 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
retval = -ENODEV;
if (!fstype)
goto out;
t = fstype->name;
fops = NULL;
memset(&dummy, 0, sizeof(dummy));
if (fstype->fs_flags & FS_REQUIRES_DEV) {
dentry = namei(dev_name);
retval = PTR_ERR(dentry);
......@@ -984,17 +977,15 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
if (MAJOR(dev) >= MAX_BLKDEV)
goto dput_and_out;
fops = get_blkfops(MAJOR(dev));
retval = -ENOTBLK;
if (!fops)
dummy.f_op = get_blkfops(MAJOR(dev));
if (!dummy.f_op)
goto dput_and_out;
if (fops->open) {
struct file dummy; /* allows read-write or read-only flag */
memset(&dummy, 0, sizeof(dummy));
if (dummy.f_op->open) {
dummy.f_dentry = dentry;
dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
retval = fops->open(inode, &dummy);
retval = dummy.f_op->open(inode, &dummy);
if (retval)
goto dput_and_out;
}
......@@ -1009,22 +1000,28 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
flags = new_flags & ~MS_MGC_MSK;
retval = copy_mount_options(data, &page);
if (retval < 0) {
put_unnamed_dev(dev);
goto dput_and_out;
}
if (retval < 0)
goto clean_up;
}
retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
retval = do_mount(dev, dev_name, dir_name, fstype->name, flags,
(void *) page);
free_page(page);
if (retval && fops && fops->release) {
fops->release(inode, NULL);
put_unnamed_dev(dev);
}
if (retval)
goto clean_up;
dput_and_out:
dput(dentry);
out:
unlock_kernel();
return retval;
clean_up:
if (dummy.f_op) {
if (dummy.f_op->release)
dummy.f_op->release(inode, NULL);
} else
put_unnamed_dev(dev);
goto dput_and_out;
}
__initfunc(static void do_mount_root(void))
......
......@@ -104,6 +104,7 @@ extern void d_delete(struct dentry *);
/* allocate/de-allocate */
extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
extern void prune_dcache(int);
extern void shrink_dcache_sb(struct super_block *);
extern int d_invalidate(struct dentry *);
#define shrink_dcache() prune_dcache(0)
......
......@@ -42,9 +42,10 @@
/* And dynamically-tunable limits and defaults: */
extern int max_inodes;
extern int max_files, nr_files;
extern int max_files, nr_files, nr_free_files;
#define NR_INODE 4096 /* this should be bigger than NR_FILE */
#define NR_FILE 1024 /* this can well be larger on a larger system */
#define NR_RESERVED_FILES 10 /* reserved for root */
#define MAY_EXEC 1
#define MAY_WRITE 2
......@@ -628,6 +629,10 @@ extern struct inode_operations chrdev_inode_operations;
extern void init_fifo(struct inode * inode);
extern struct inode_operations fifo_inode_operations;
/* Invalid inode operations -- fs/bad_inode.c */
extern void make_bad_inode(struct inode * inode);
extern int is_bad_inode(struct inode * inode);
extern struct file_operations connecting_fifo_fops;
extern struct file_operations read_fifo_fops;
extern struct file_operations write_fifo_fops;
......
......@@ -3,7 +3,14 @@
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
......@@ -15,24 +22,48 @@ struct list_head {
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
static inline void list_add(struct list_head *new, struct list_head *head)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head * new,
struct list_head * prev,
struct list_head * next)
{
struct list_head *next = head->next;
next->prev = new;
new->next = next;
new->prev = head;
head->next = new;
new->prev = prev;
prev->next = new;
}
static inline void list_del(struct list_head *entry)
/*
* Insert a new entry after the specified head..
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
struct list_head *next, *prev;
next = entry->next;
prev = entry->prev;
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static inline int list_empty(struct list_head *head)
{
return head->next == head;
......
......@@ -296,6 +296,8 @@ extern unsigned long get_unmapped_area(unsigned long, unsigned long);
extern unsigned long page_unuse(unsigned long);
extern int shrink_mmap(int, int);
extern void truncate_inode_pages(struct inode *, unsigned long);
extern unsigned long get_cached_page(struct inode *, unsigned long, int);
extern void put_cached_page(unsigned long);
#define GFP_BUFFER 0x00
#define GFP_ATOMIC 0x01
......
......@@ -129,14 +129,6 @@ struct nfs_sattr {
struct nfs_time mtime;
};
struct nfs_entry {
__u32 fileid;
char * name;
unsigned int length:31,
eof:1;
__u32 cookie;
};
struct nfs_fsinfo {
__u32 tsize;
__u32 bsize;
......
......@@ -125,7 +125,7 @@ extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
const char *name);
extern int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
u32 cookie, unsigned int size, struct nfs_entry *entry);
u32 cookie, unsigned int size, __u32 *entry);
extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *res);
......@@ -138,7 +138,7 @@ extern struct super_block *nfs_read_super(struct super_block *sb,
extern int init_nfs_fs(void);
extern struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
struct nfs_fattr *fattr);
extern void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_revalidate(struct inode *);
extern int _nfs_revalidate_inode(struct nfs_server *, struct inode *);
......
......@@ -237,13 +237,15 @@ struct proc_dir_entry {
unsigned long size;
struct inode_operations * ops;
int (*get_info)(char *, char **, off_t, int, int);
void (*fill_inode)(struct inode *);
void (*fill_inode)(struct inode *, int);
struct proc_dir_entry *next, *parent, *subdir;
void *data;
int (*read_proc)(char *page, char **start, off_t off,
int count, int *eof, void *data);
int (*write_proc)(struct file *file, const char *buffer,
unsigned long count, void *data);
unsigned int count; /* use count */
int deleted; /* delete flag */
};
extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
......
......@@ -9,6 +9,7 @@
#ifndef _LINUX_SMB_FS_H
#define _LINUX_SMB_FS_H
#include <linux/dirent.h>
#include <linux/smb.h>
/*
......@@ -71,30 +72,24 @@ extern struct inode_operations smb_file_inode_operations;
/* linux/fs/smbfs/dir.c */
extern struct inode_operations smb_dir_inode_operations;
struct smb_inode_info *smb_find_inode(struct smb_sb_info *server, ino_t ino);
void smb_free_inode_info(struct smb_inode_info *i);
void smb_free_all_inodes(struct smb_sb_info *server);
void smb_init_root(struct smb_sb_info *server);
int smb_stat_root(struct smb_sb_info *server);
void smb_init_dir_cache(void);
void smb_invalid_dir_cache(struct inode *);
void smb_free_dir_cache(void);
void smb_init_root(struct smb_sb_info *);
int smb_stat_root(struct smb_sb_info *);
void smb_renew_times(struct dentry *);
/* linux/fs/smbfs/ioctl.c */
int smb_ioctl (struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg);
/* linux/fs/smbfs/inode.c */
struct super_block *smb_read_super(struct super_block *sb,
void *raw_data, int silent);
struct super_block *smb_read_super(struct super_block *, void *, int);
extern int init_smb_fs(void);
void smb_invalidate_inodes(struct smb_sb_info *server);
int smb_revalidate_inode(struct inode *i);
int smb_refresh_inode(struct inode *i);
int smb_notify_change(struct inode *inode, struct iattr *attr);
void smb_invalidate_connection(struct smb_sb_info *server);
int smb_conn_is_valid(struct smb_sb_info *server);
unsigned long smb_invent_inos(unsigned long n);
void smb_invalidate_inodes(struct smb_sb_info *);
int smb_revalidate_inode(struct inode *);
int smb_refresh_inode(struct inode *);
int smb_notify_change(struct inode *, struct iattr *);
void smb_invalidate_connection(struct smb_sb_info *);
int smb_conn_is_valid(struct smb_sb_info *);
unsigned long smb_invent_inos(unsigned long);
struct inode *smb_iget(struct super_block *, struct smb_fattr *);
/* linux/fs/smbfs/proc.c */
......@@ -105,6 +100,7 @@ __u8 *smb_setup_header(struct smb_sb_info *server, __u8 command,
int smb_offerconn(struct smb_sb_info *server);
int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt);
int smb_close(struct inode *);
void smb_close_dentry(struct dentry *);
int smb_open(struct dentry *, int);
static inline int
smb_is_open(struct inode *i)
......@@ -112,34 +108,31 @@ smb_is_open(struct inode *i)
return (i->u.smbfs_i.open == SMB_SERVER(i)->generation);
}
int smb_proc_read(struct inode *, off_t, long, char *);
int smb_proc_read(struct inode *, off_t, int, char *);
int smb_proc_write(struct inode *, off_t, int, const char *);
int smb_proc_create(struct dentry *, struct qstr *, __u16, time_t);
int smb_proc_mv(struct dentry *, struct qstr *, struct dentry *, struct qstr *);
int smb_proc_mkdir(struct dentry *, struct qstr *);
int smb_proc_rmdir(struct dentry *, struct qstr *);
int smb_proc_unlink(struct dentry *dir, struct qstr *);
int smb_proc_readdir(struct dentry *dir, int fpos, int cache_size, struct smb_dirent *entry);
int smb_proc_getattr(struct dentry *dir, struct qstr *name,
struct smb_fattr *entry);
int smb_proc_setattr(struct smb_sb_info *server,
struct dentry *dir,
struct smb_fattr *new_finfo);
int smb_proc_dskattr(struct super_block *sb, struct statfs *attr);
int smb_proc_reconnect(struct smb_sb_info *server);
int smb_proc_connect(struct smb_sb_info *server);
int smb_proc_disconnect(struct smb_sb_info *server);
int smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length);
int smb_proc_readdir(struct dentry *, int, void *);
int smb_proc_getattr(struct dentry *, struct qstr *, struct smb_fattr *);
int smb_proc_setattr(struct smb_sb_info *, struct dentry *, struct smb_fattr *);
int smb_proc_dskattr(struct super_block *, struct statfs *);
int smb_proc_reconnect(struct smb_sb_info *);
int smb_proc_connect(struct smb_sb_info *);
int smb_proc_disconnect(struct smb_sb_info *);
int smb_proc_trunc(struct smb_sb_info *, __u16, __u32);
void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *);
/* linux/fs/smbfs/sock.c */
int smb_valid_socket(struct inode *);
void smb_close_socket(struct smb_sb_info *);
int smb_release(struct smb_sb_info *server);
int smb_connect(struct smb_sb_info *server);
int smb_request(struct smb_sb_info *server);
int smb_request_read_raw(struct smb_sb_info *server,
unsigned char *target, int max_len);
int smb_request_write_raw(struct smb_sb_info *server,
unsigned const char *source, int length);
int smb_request_read_raw(struct smb_sb_info *, unsigned char *, int);
int smb_request_write_raw(struct smb_sb_info *, unsigned const char *, int);
int smb_catch_keepalive(struct smb_sb_info *server);
int smb_dont_catch_keepalive(struct smb_sb_info *server);
int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
......@@ -151,6 +144,72 @@ int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
/* linux/fs/smbfs/mmap.c */
int smb_mmap(struct file * file, struct vm_area_struct * vma);
/* fs/smbfs/cache.c */
/*
* The cache index describes the pages mapped starting
* at offset PAGE_SIZE. We keep only a minimal amount
* of information here.
*/
struct cache_index {
unsigned short num_entries;
unsigned short space;
struct cache_block * block;
};
#define NINDEX (PAGE_SIZE-64)/sizeof(struct cache_index)
/*
* The cache head is mapped as the page at offset 0.
*/
struct cache_head {
int valid;
int status; /* error code or 0 */
int entries; /* total entries */
int pages; /* number of data pages */
int idx; /* index of current data page */
struct cache_index index[NINDEX];
};
/*
* An array of cache_entry structures holds information
* for each object in the cache_block.
*/
struct cache_entry {
ino_t ino;
unsigned short namelen;
unsigned short offset;
};
/*
* The cache blocks hold the actual data. The entry table grows up
* while the names grow down, and we have space until they meet.
*/
struct cache_block {
union {
struct cache_entry table[1];
char names[PAGE_SIZE];
} cb_data;
};
/*
* To return an entry, we can pass a reference to the
* name instead of having to copy it.
*/
struct cache_dirent {
ino_t ino;
unsigned long pos;
int len;
char * name;
};
struct cache_head * smb_get_dircache(struct dentry *);
void smb_init_dircache(struct cache_head *);
void smb_free_dircache(struct cache_head *);
int smb_refill_dircache(struct cache_head *, struct dentry *);
void smb_add_to_cache(struct cache_head *, struct dirent *, off_t);
int smb_find_in_cache(struct cache_head *, off_t, struct cache_dirent *);
void smb_invalid_dir_cache(struct inode *);
#endif /* __KERNEL__ */
#endif /* _LINUX_SMB_FS_H */
......@@ -22,11 +22,13 @@ struct smb_inode_info {
* (open == generation).
*/
unsigned int open;
void * dentry; /* The dentry we were opened with */
__u16 fileid; /* What id to handle a file with? */
__u16 attr; /* Attribute fields, DOS value */
__u16 access; /* Access bits. */
__u16 cache_valid; /* dircache valid? */
unsigned long oldmtime; /* last time refreshed */
void * dentry; /* The dentry we were opened with */
};
#endif
......
......@@ -15,6 +15,11 @@
#include <linux/smb.h>
#include <linux/smb_mount.h>
/* Get the server for the specified dentry */
#define server_from_dentry(dentry) &dentry->d_sb->u.smbfs_sb
#define SB_of(server) ((struct super_block *) ((char *)(server) - \
(unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
struct smb_sb_info {
enum smb_conn_state state;
struct file * sock_file;
......@@ -29,6 +34,7 @@ struct smb_sb_info {
struct smb_conn_opt opt;
struct semaphore sem;
struct wait_queue * wait;
__u32 packet_size;
unsigned char * packet;
......
......@@ -143,7 +143,7 @@ void rpc_del_timer(struct rpc_task *);
void rpc_delay(struct rpc_task *, unsigned long);
void * rpc_allocate(unsigned int flags, unsigned int);
void rpc_free(void *);
void rpciod_up(void);
int rpciod_up(void);
void rpciod_down(void);
extern __inline__ void *
......
......@@ -208,7 +208,6 @@ static inline int dup_mmap(struct mm_struct * mm)
struct vm_area_struct * mpnt, *tmp, **pprev;
int retval;
mm->mmap = mm->mmap_cache = NULL;
flush_cache_mm(current->mm);
pprev = &mm->mmap;
for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
......@@ -254,8 +253,7 @@ static inline int dup_mmap(struct mm_struct * mm)
if (retval)
goto fail_nomem;
}
flush_tlb_mm(current->mm);
return 0;
retval = 0;
fail_nomem:
flush_tlb_mm(current->mm);
......@@ -276,7 +274,10 @@ struct mm_struct * mm_alloc(void)
mm->count = 1;
mm->def_flags = 0;
mm->mmap_sem = MUTEX;
mm->pgd = NULL;
/*
* Leave mm->pgd set to the parent's pgd
* so that pgd_offset() is always valid.
*/
mm->mmap = mm->mmap_cache = NULL;
/* It has not run yet, so cannot be present in anyone's
......@@ -324,10 +325,12 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
goto free_mm;
retval = dup_mmap(mm);
if (retval)
goto free_mm;
goto free_pt;
return 0;
free_mm:
mm->pgd = NULL;
free_pt:
tsk->mm = NULL;
mmput(mm);
fail_nomem:
......@@ -376,7 +379,13 @@ static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk
struct files_struct *oldf, *newf;
struct file **old_fds, **new_fds;
/*
* A background process may not have any files ...
*/
oldf = current->files;
if (!oldf)
return 0;
if (clone_flags & CLONE_FILES) {
oldf->count++;
return 0;
......@@ -516,7 +525,9 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
}
++total_forks;
error = p->pid;
goto fork_out;
bad_fork:
unlock_kernel();
return error;
bad_fork_cleanup_sighand:
exit_sighand(p);
......@@ -536,10 +547,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
nr_tasks--;
bad_fork_free:
free_task_struct(p);
bad_fork:
fork_out:
unlock_kernel();
return error;
goto bad_fork;
}
static void files_ctor(void *fp, kmem_cache_t *cachep, unsigned long flags)
......
......@@ -192,6 +192,8 @@ EXPORT_SYMBOL(posix_test_lock);
EXPORT_SYMBOL(posix_block_lock);
EXPORT_SYMBOL(posix_unblock_lock);
EXPORT_SYMBOL(dput);
EXPORT_SYMBOL(get_cached_page);
EXPORT_SYMBOL(put_cached_page);
#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
EXPORT_SYMBOL(do_nfsservctl);
......@@ -369,6 +371,8 @@ EXPORT_SYMBOL(read_ahead);
EXPORT_SYMBOL(get_hash_table);
EXPORT_SYMBOL(get_empty_inode);
EXPORT_SYMBOL(insert_inode_hash);
EXPORT_SYMBOL(make_bad_inode);
EXPORT_SYMBOL(is_bad_inode);
EXPORT_SYMBOL(event);
EXPORT_SYMBOL(__down);
EXPORT_SYMBOL(__up);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment