count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
start = NULL;
- if (dp->get_info) {
- /* Handle old net routines */
- n = dp->get_info(page, &start, *ppos, count);
- if (n < count)
- eof = 1;
- } else if (dp->read_proc) {
+ if (dp->read_proc) {
/*
* How to be a proc read function
* ------------------------------
int len;
int rtn = 0;
+ de = *ret;
+ if (!de)
+ de = &proc_root;
+
spin_lock(&proc_subdir_lock);
- de = &proc_root;
while (1) {
next = strchr(cp, '/');
if (!next)
lock_kernel();
spin_lock(&proc_subdir_lock);
- if (de) {
- for (de = de->subdir; de ; de = de->next) {
- if (de->namelen != dentry->d_name.len)
- continue;
- if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
- unsigned int ino;
-
- ino = de->low_ino;
- de_get(de);
- spin_unlock(&proc_subdir_lock);
- error = -EINVAL;
- inode = proc_get_inode(dir->i_sb, ino, de);
- goto out_unlock;
- }
+ for (de = de->subdir; de ; de = de->next) {
+ if (de->namelen != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
+ unsigned int ino;
+
+ ino = de->low_ino;
+ de_get(de);
+ spin_unlock(&proc_subdir_lock);
+ error = -EINVAL;
+ inode = proc_get_inode(dir->i_sb, ino, de);
+ goto out_unlock;
}
}
spin_unlock(&proc_subdir_lock);
d_add(dentry, inode);
return NULL;
}
- de_put(de);
+ if (de)
+ de_put(de);
return ERR_PTR(error);
}
lock_kernel();
ino = inode->i_ino;
- if (!de) {
- ret = -EINVAL;
- goto out;
- }
i = filp->f_pos;
switch (i) {
case 0:
/* make sure name is valid */
if (!name || !strlen(name)) goto out;
- if (!(*parent) && xlate_proc_name(name, parent, &fn) != 0)
+ if (xlate_proc_name(name, parent, &fn) != 0)
goto out;
/* At this point there must not be any '/' characters beyond *fn */
ent->pde_users = 0;
spin_lock_init(&ent->pde_unload_lock);
ent->pde_unload_completion = NULL;
+ INIT_LIST_HEAD(&ent->pde_openers);
out:
return ent;
}
return ent;
}
+struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
+ struct proc_dir_entry *parent)
+{
+ struct proc_dir_entry *ent;
+
+ ent = __proc_create(&parent, name, S_IFDIR | S_IRUGO | S_IXUGO, 2);
+ if (ent) {
+ ent->data = net;
+ if (proc_register(parent, ent) < 0) {
+ kfree(ent);
+ ent = NULL;
+ }
+ }
+ return ent;
+}
+EXPORT_SYMBOL_GPL(proc_net_mkdir);
+
struct proc_dir_entry *proc_mkdir(const char *name,
struct proc_dir_entry *parent)
{
return ent;
}
-struct proc_dir_entry *proc_create(const char *name, mode_t mode,
- struct proc_dir_entry *parent,
- const struct file_operations *proc_fops)
+struct proc_dir_entry *proc_create_data(const char *name, mode_t mode,
+ struct proc_dir_entry *parent,
+ const struct file_operations *proc_fops,
+ void *data)
{
struct proc_dir_entry *pde;
nlink_t nlink;
if (!pde)
goto out;
pde->proc_fops = proc_fops;
+ pde->data = data;
if (proc_register(parent, pde) < 0)
goto out_free;
return pde;
const char *fn = name;
int len;
- if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
+ if (xlate_proc_name(name, &parent, &fn) != 0)
return;
len = strlen(fn);
spin_unlock(&de->pde_unload_lock);
continue_removing:
+ spin_lock(&de->pde_unload_lock);
+ while (!list_empty(&de->pde_openers)) {
+ struct pde_opener *pdeo;
+
+ pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh);
+ list_del(&pdeo->lh);
+ spin_unlock(&de->pde_unload_lock);
+ pdeo->release(pdeo->inode, pdeo->file);
+ kfree(pdeo);
+ spin_lock(&de->pde_unload_lock);
+ }
+ spin_unlock(&de->pde_unload_lock);
+
if (S_ISDIR(de->mode))
parent->nlink--;
de->nlink = 0;
- if (de->subdir) {
- printk(KERN_WARNING "%s: removing non-empty directory "
+ WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory "
"'%s/%s', leaking at least '%s'\n", __func__,
de->parent->name, de->name, de->subdir->name);
- WARN_ON(1);
- }
if (atomic_dec_and_test(&de->count))
free_proc_entry(de);
}