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;
err = -EINVAL;
if ((count < 11) || (count > 256))
goto _err;
}
err = -ENOMEM;
memsize = sizeof(struct binfmt_entry) + count;
if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
err = -ENOMEM;
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,37 +61,54 @@ static inline void d_free(struct dentry *dentry)
*/
void dput(struct dentry *dentry)
{
if (dentry) {
int count;
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;
}
list_del(&dentry->d_lru);
if (list_empty(&dentry->d_hash)) {
struct inode *inode = dentry->d_inode;
struct dentry * parent;
if (inode)
iput(inode);
parent = dentry->d_parent;
d_free(dentry);
if (dentry == parent)
return;
dentry = parent;
goto repeat;
}
list_add(&dentry->d_lru, &dentry_unused);
out:
if (count >= 0) {
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;
if (inode)
iput(inode);
parent = dentry->d_parent;
d_free(dentry);
if (dentry == parent)
return;
dentry = parent;
goto repeat;
}
list_add(&dentry->d_lru, &dentry_unused);
}
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;
f = free_filps;
if (!f)
goto get_more;
remove_filp(f);
got_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)) {
if (nr_free_files > NR_RESERVED_FILES) {
used_one:
f = free_filps;
remove_filp(f);
nr_free_files--;
new_one:
memset(f, 0, sizeof(*f));
f->f_count = 1;
f->f_version = ++event;
put_inuse(f);
return f;
}
/*
* 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,8 +172,17 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_ops->exp_unlock();
}
nlm_shutdown_hosts();
/*
* 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
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;
nlmsvc_pid = 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,11 +232,14 @@ 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);
int error = dir->i_op->lookup(dir, dentry);
result = ERR_PTR(error);
if (!error)
result = dget(dentry->d_mounts);
dput(dentry);
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 */
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_up();
return sb;
}
/* 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)
unlock_super(sb);
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;
column += 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,17 +46,14 @@ 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 */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
&proc_file_operations, /* default proc file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
......@@ -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;
if (parent)
fn = name;
else {
if (xlate_proc_name(name, &parent, &fn))
return NULL;
}
struct proc_dir_entry *ent = NULL;
const char *fn = name;
int len;
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,23 +153,29 @@ 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) {
inode->u.generic_ip = (void *) de;
if (de) {
if (de->mode) {
inode->i_mode = de->mode;
inode->i_uid = de->uid;
inode->i_gid = de->gid;
}
if (de->size)
inode->i_size = de->size;
if (de->ops)
inode->i_op = de->ops;
if (de->nlink)
inode->i_nlink = de->nlink;
if (de->fill_inode)
de->fill_inode(inode);
/* 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) {
inode->i_mode = de->mode;
inode->i_uid = de->uid;
inode->i_gid = de->gid;
}
if (de->size)
inode->i_size = de->size;
if (de->ops)
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, 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) {
s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
parse_options(data, &s->s_root->d_inode->i_uid, &s->s_root->d_inode->i_gid);
return s;
out_no_root:
printk("proc_read_super: get root inode failed\n");
iput(root_inode);
s->s_dev = 0;
unlock_super(s);
return NULL;
}
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;
d_add(dentry, inode);
return 0;
if (inode) {
dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
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,8 +195,8 @@ static int
smb_updatepage(struct inode *inode, struct page *page, const char *buffer,
unsigned long offset, unsigned int count, int sync)
{
u8 *page_addr;
int result;
unsigned long page_addr = page_address(page);
int result;
pr_debug("SMB: smb_updatepage(%x/%ld %d@%ld, sync=%d)\n",
inode->i_dev, inode->i_ino,
......@@ -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,
......
This diff is collapsed.
......@@ -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);
......
......@@ -147,7 +147,7 @@ static ctl_table kern_table[] = {
0444, NULL, &proc_dointvec},
{KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
0644, NULL, &proc_dointvec},
{KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
{KERN_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
0444, NULL, &proc_dointvec},
{KERN_MAXFILE, "file-max", &max_files, sizeof(int),
0644, NULL, &proc_dointvec},
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -54,15 +54,16 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
}
clnt->cl_binding = 1;
task->tk_status = 0;
if (!(pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot))) {
task->tk_status = -EACCES;
task->tk_status = -EACCES; /* why set this? returns -EIO below */
if (!(pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot)))
goto bailout;
}
if (!(child = rpc_new_child(pmap_clnt, task))) {
rpc_destroy_client(pmap_clnt);
task->tk_status = 0;
/*
* Note: rpc_new_child will release client after a failure.
*/
if (!(child = rpc_new_child(pmap_clnt, task)))
goto bailout;
}
/* Setup the call info struct */
rpc_call_setup(child, PMAP_GETPORT, map, &clnt->cl_port, 0);
......
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