static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct ctl_table_header *head = grab_header(dir); struct ctl_table *table = PROC_I(dir)->sysctl_entry; struct ctl_table_header *h = NULL; struct qstr *name = &dentry->d_name; struct ctl_table *p; struct inode *inode; struct dentry *err = ERR_PTR(-ENOENT); if (IS_ERR(head)) return ERR_CAST(head); if (table && !table->child) { WARN_ON(1); goto out; } table = table ? table->child : head->ctl_table; p = find_in_table(table, name); if (!p) { for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) { if (h->attached_to != table) continue; p = find_in_table(h->attached_by, name); if (p) break; } } if (!p) goto out; if (gr_handle_sysctl(p, MAY_EXEC)) goto out; err = ERR_PTR(-ENOMEM); inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); if (h) sysctl_head_finish(h); if (!inode) goto out; err = NULL; d_set_d_op(dentry, &proc_sys_dentry_operations); d_add(dentry, inode); out: sysctl_head_finish(head); return err; }
static int proc_sys_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct ctl_table_header *head, struct ctl_table *table) { struct dentry *child, *dir = filp->f_path.dentry; struct inode *inode; struct qstr qname; ino_t ino = 0; unsigned type = DT_UNKNOWN; qname.name = table->procname; qname.len = strlen(table->procname); qname.hash = full_name_hash(qname.name, qname.len); child = d_lookup(dir, &qname); if (!child) { child = d_alloc(dir, &qname); if (child) { inode = proc_sys_make_inode(dir->d_sb, head, table); if (!inode) { dput(child); return -ENOMEM; } else { d_set_d_op(child, &proc_sys_dentry_operations); d_add(child, inode); } } else { return -ENOMEM; } } inode = child->d_inode; ino = inode->i_ino; type = inode->i_mode >> 12; dput(child); return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type); }