134 lines
3.0 KiB
C
134 lines
3.0 KiB
C
/* Reduced and adapted from Linux: fs/proc/inode.c: proc_reg_open
|
|
(GPL v2.0). */
|
|
|
|
/* Types. */
|
|
|
|
typedef unsigned char u8;
|
|
typedef _Bool bool;
|
|
typedef unsigned int gfp_t;
|
|
|
|
struct file;
|
|
struct kmem_cache;
|
|
struct proc_dir_entry;
|
|
|
|
struct inode { /* [...snip...] */ };
|
|
|
|
enum {
|
|
PROC_ENTRY_PERMANENT = 1U << 0,
|
|
};
|
|
|
|
struct proc_ops {
|
|
/* [...snip...] */
|
|
int (*proc_open)(struct inode *, struct file *);
|
|
/* [...snip...] */
|
|
int (*proc_release)(struct inode *, struct file *);
|
|
/* [...snip...] */
|
|
};
|
|
|
|
struct proc_dir_entry {
|
|
/* [...snip...] */
|
|
struct completion *pde_unload_completion;
|
|
/* [...snip...] */
|
|
union {
|
|
const struct proc_ops *proc_ops;
|
|
const struct file_operations *proc_dir_ops;
|
|
};
|
|
/* [...snip...] */
|
|
u8 flags;
|
|
/* [...snip...] */
|
|
};
|
|
|
|
struct pde_opener {
|
|
/* [...snip...] */
|
|
struct file *file;
|
|
/* [...snip...] */
|
|
};
|
|
|
|
struct proc_inode {
|
|
/* [...snip...] */
|
|
struct proc_dir_entry *pde;
|
|
/* [...snip...] */
|
|
struct inode vfs_inode;
|
|
};
|
|
|
|
/* Data. */
|
|
|
|
static struct kmem_cache *pde_opener_cache __attribute__((__section__(".data..ro_after_init")));
|
|
|
|
/* Functions. */
|
|
|
|
void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags) __attribute__((__malloc__));
|
|
void kmem_cache_free(struct kmem_cache *, void *);
|
|
|
|
static inline bool pde_is_permanent(const struct proc_dir_entry *pde)
|
|
{
|
|
return pde->flags & PROC_ENTRY_PERMANENT;
|
|
}
|
|
|
|
static inline struct proc_inode *PROC_I(const struct inode *inode)
|
|
{
|
|
void *__mptr = (void *)(inode);
|
|
return ((struct proc_inode *)(__mptr - __builtin_offsetof(struct proc_inode, vfs_inode)));
|
|
}
|
|
|
|
static inline struct proc_dir_entry *PDE(const struct inode *inode)
|
|
{
|
|
return PROC_I(inode)->pde;
|
|
}
|
|
|
|
/* We don't want to emit bogus use of uninitialized value 'pdeo'
|
|
warnings from -Wanalyzer-use-of-uninitialized-value in this function;
|
|
these would require following infeasible paths in which "release" is
|
|
first NULL (to avoid the initialization of "pdeo") and then is non-NULL
|
|
(to access "pdeo").
|
|
|
|
"release" is sufficiently complicated in this function to hit the
|
|
complexity limit for symbolic values during enode exploration. */
|
|
|
|
static int proc_reg_open(struct inode *inode, struct file *file)
|
|
{
|
|
struct proc_dir_entry *pde = PDE(inode);
|
|
int rv = 0;
|
|
typeof(((struct proc_ops*)0)->proc_open) open;
|
|
typeof(((struct proc_ops*)0)->proc_release) release;
|
|
struct pde_opener *pdeo;
|
|
|
|
if (pde_is_permanent(pde)) {
|
|
open = pde->proc_ops->proc_open;
|
|
if (open)
|
|
rv = open(inode, file);
|
|
return rv;
|
|
}
|
|
|
|
/* [...snip...] */
|
|
|
|
release = pde->proc_ops->proc_release;
|
|
if (release) {
|
|
pdeo = kmem_cache_alloc(pde_opener_cache,
|
|
((( gfp_t)(0x400u|0x800u))
|
|
| (( gfp_t)0x40u)
|
|
| (( gfp_t)0x80u)));
|
|
if (!pdeo) {
|
|
rv = -12;
|
|
goto out_unuse;
|
|
}
|
|
}
|
|
|
|
open = pde->proc_ops->proc_open;
|
|
if (open)
|
|
rv = open(inode, file);
|
|
|
|
if (release) {
|
|
if (rv == 0) {
|
|
|
|
pdeo->file = file; /* { dg-bogus "uninit" } */
|
|
/* [...snip...] */
|
|
} else
|
|
kmem_cache_free(pde_opener_cache, pdeo); /* { dg-bogus "uninit" } */
|
|
}
|
|
|
|
out_unuse:
|
|
/* [...snip...] */
|
|
return rv;
|
|
}
|