Skip to content
This repository has been archived by the owner on Feb 26, 2020. It is now read-only.

Commit

Permalink
Linux 3.10 compat: Do not rely on struct proc_dir_entry definition
Browse files Browse the repository at this point in the history
Linux kernel commit torvalds/linux#59d8053f moved the definition of
struct proc_dir_entry from include/linux/proc_fs.h to the private
header fs/proc/internal.h. The SPL relied on that to map Solaris'
kstat to entries in /proc/spl/kstat.

Since the proc_dir_entry structure is now private the only safe
thing to do is wrap the opaque proc handle with our own structure.
This actually ends up simplify the code and is good because it
moves us away from depending on implementation details of /proc.

Signed-off-by: Richard Yao <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Issue #257
  • Loading branch information
ryao authored and behlendorf committed Jul 8, 2013
1 parent 79a7ab2 commit f2a745c
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 88 deletions.
3 changes: 0 additions & 3 deletions include/linux/proc_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@
#endif

extern struct proc_dir_entry *proc_spl_kstat;
struct proc_dir_entry *proc_dir_entry_find(struct proc_dir_entry *root,
const char *str);
int proc_dir_entries(struct proc_dir_entry *root);

int spl_proc_init(void);
void spl_proc_fini(void);
Expand Down
8 changes: 8 additions & 0 deletions include/sys/kstat.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ struct kstat_s;
typedef int kid_t; /* unique kstat id */
typedef int kstat_update_t(struct kstat_s *, int); /* dynamic update cb */

typedef struct kstat_module {
char ksm_name[KSTAT_STRLEN+1]; /* module name */
struct list_head ksm_module_list; /* module linkage */
struct list_head ksm_kstat_list; /* list of kstat entries */
struct proc_dir_entry *ksm_proc; /* proc entry */
} kstat_module_t;

typedef struct kstat_s {
int ks_magic; /* magic value */
kid_t ks_kid; /* unique kstat ID */
Expand All @@ -102,6 +109,7 @@ typedef struct kstat_s {
void *ks_private; /* private data */
kmutex_t ks_lock; /* kstat data lock */
struct list_head ks_list; /* kstat linkage */
kstat_module_t *ks_owner; /* kstat module linkage */
} kstat_t;

typedef struct kstat_named_s {
Expand Down
135 changes: 85 additions & 50 deletions module/spl/spl-kstat.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
#define PDE_DATA(x) (PDE(x)->data)
#endif

static spinlock_t kstat_lock;
static struct list_head kstat_list;
static kmutex_t kstat_module_lock;
static struct list_head kstat_module_list;
static kid_t kstat_id;

static void
Expand Down Expand Up @@ -351,6 +351,47 @@ static struct seq_operations kstat_seq_ops = {
.stop = kstat_seq_stop,
};

static kstat_module_t *
kstat_find_module(char *name)
{
kstat_module_t *module;

list_for_each_entry(module, &kstat_module_list, ksm_module_list)
if (strncmp(name, module->ksm_name, KSTAT_STRLEN) == 0)
return (module);

return (NULL);
}

static kstat_module_t *
kstat_create_module(char *name)
{
kstat_module_t *module;
struct proc_dir_entry *pde;

pde = proc_mkdir(name, proc_spl_kstat);
if (pde == NULL)
return (NULL);

module = kmem_alloc(sizeof (kstat_module_t), KM_SLEEP);
module->ksm_proc = pde;
strlcpy(module->ksm_name, name, KSTAT_STRLEN+1);
INIT_LIST_HEAD(&module->ksm_kstat_list);
list_add_tail(&module->ksm_module_list, &kstat_module_list);

return (module);

}

static void
kstat_delete_module(kstat_module_t *module)
{
ASSERT(list_empty(&module->ksm_kstat_list));
remove_proc_entry(module->ksm_name, proc_spl_kstat);
list_del(&module->ksm_module_list);
kmem_free(module, sizeof(kstat_module_t));
}

static int
proc_kstat_open(struct inode *inode, struct file *filp)
{
Expand Down Expand Up @@ -393,10 +434,10 @@ __kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
if (ksp == NULL)
return ksp;

spin_lock(&kstat_lock);
mutex_enter(&kstat_module_lock);
ksp->ks_kid = kstat_id;
kstat_id++;
spin_unlock(&kstat_lock);
mutex_exit(&kstat_module_lock);

ksp->ks_magic = KS_MAGIC;
mutex_init(&ksp->ks_lock, NULL, MUTEX_DEFAULT, NULL);
Expand Down Expand Up @@ -459,71 +500,64 @@ EXPORT_SYMBOL(__kstat_create);
void
__kstat_install(kstat_t *ksp)
{
struct proc_dir_entry *de_module, *de_name;
kstat_module_t *module;
kstat_t *tmp;
int rc = 0;
SENTRY;

spin_lock(&kstat_lock);

/* Item may only be added to the list once */
list_for_each_entry(tmp, &kstat_list, ks_list) {
if (tmp == ksp) {
spin_unlock(&kstat_lock);
SGOTO(out, rc = -EEXIST);
}
}
ASSERT(ksp);

list_add_tail(&ksp->ks_list, &kstat_list);
spin_unlock(&kstat_lock);
mutex_enter(&kstat_module_lock);

de_module = proc_dir_entry_find(proc_spl_kstat, ksp->ks_module);
if (de_module == NULL) {
de_module = proc_mkdir(ksp->ks_module, proc_spl_kstat);
if (de_module == NULL)
SGOTO(out, rc = -EUNATCH);
module = kstat_find_module(ksp->ks_module);
if (module == NULL) {
module = kstat_create_module(ksp->ks_module);
if (module == NULL)
goto out;
}

de_name = create_proc_entry(ksp->ks_name, 0444, de_module);
if (de_name == NULL)
SGOTO(out, rc = -EUNATCH);
/*
* Only one entry by this name per-module, on failure the module
* shouldn't be deleted because we know it has at least one entry.
*/
list_for_each_entry(tmp, &module->ksm_kstat_list, ks_list)
if (strncmp(tmp->ks_name, ksp->ks_name, KSTAT_STRLEN) == 0)
goto out;

list_add_tail(&ksp->ks_list, &module->ksm_kstat_list);

mutex_enter(&ksp->ks_lock);
ksp->ks_proc = de_name;
de_name->proc_fops = &proc_kstat_operations;
de_name->data = (void *)ksp;
ksp->ks_owner = module;
ksp->ks_proc = proc_create_data(ksp->ks_name, 0444,
module->ksm_proc, &proc_kstat_operations, (void *)ksp);
if (ksp->ks_proc == NULL) {
list_del_init(&ksp->ks_list);
if (list_empty(&module->ksm_kstat_list))
kstat_delete_module(module);
}
mutex_exit(&ksp->ks_lock);
out:
if (rc) {
spin_lock(&kstat_lock);
list_del_init(&ksp->ks_list);
spin_unlock(&kstat_lock);
}

SEXIT;
mutex_exit(&kstat_module_lock);
}
EXPORT_SYMBOL(__kstat_install);

void
__kstat_delete(kstat_t *ksp)
{
struct proc_dir_entry *de_module;
kstat_module_t *module = ksp->ks_owner;

spin_lock(&kstat_lock);
list_del_init(&ksp->ks_list);
spin_unlock(&kstat_lock);
mutex_enter(&kstat_module_lock);
list_del_init(&ksp->ks_list);
mutex_exit(&kstat_module_lock);

if (ksp->ks_proc) {
de_module = ksp->ks_proc->parent;
remove_proc_entry(ksp->ks_name, de_module);
if (ksp->ks_proc) {
remove_proc_entry(ksp->ks_name, module->ksm_proc);

/* Remove top level module directory if it's empty */
if (proc_dir_entries(de_module) == 0)
remove_proc_entry(de_module->name, de_module->parent);
/* Remove top level module directory if it's empty */
if (list_empty(&module->ksm_kstat_list))
kstat_delete_module(module);
}

if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL))
kmem_free(ksp->ks_data, ksp->ks_data_size);
kmem_free(ksp->ks_data, ksp->ks_data_size);

mutex_destroy(&ksp->ks_lock);
kmem_free(ksp, sizeof(*ksp));
Expand All @@ -536,8 +570,8 @@ int
spl_kstat_init(void)
{
SENTRY;
spin_lock_init(&kstat_lock);
INIT_LIST_HEAD(&kstat_list);
mutex_init(&kstat_module_lock, NULL, MUTEX_DEFAULT, NULL);
INIT_LIST_HEAD(&kstat_module_list);
kstat_id = 0;
SRETURN(0);
}
Expand All @@ -546,7 +580,8 @@ void
spl_kstat_fini(void)
{
SENTRY;
ASSERT(list_empty(&kstat_list));
ASSERT(list_empty(&kstat_module_list));
mutex_destroy(&kstat_module_lock);
SEXIT;
}

37 changes: 2 additions & 35 deletions module/spl/spl-proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1120,39 +1120,6 @@ static struct ctl_table spl_root[] = {
{ 0 }
};

static int
proc_dir_entry_match(int len, const char *name, struct proc_dir_entry *de)
{
if (de->namelen != len)
return 0;

return !memcmp(name, de->name, len);
}

struct proc_dir_entry *
proc_dir_entry_find(struct proc_dir_entry *root, const char *str)
{
struct proc_dir_entry *de;

for (de = root->subdir; de; de = de->next)
if (proc_dir_entry_match(strlen(str), str, de))
return de;

return NULL;
}

int
proc_dir_entries(struct proc_dir_entry *root)
{
struct proc_dir_entry *de;
int i = 0;

for (de = root->subdir; de; de = de->next)
i++;

return i;
}

int
spl_proc_init(void)
{
Expand All @@ -1174,11 +1141,11 @@ spl_proc_init(void)
if (proc_spl_kmem == NULL)
SGOTO(out, rc = -EUNATCH);

proc_spl_kmem_slab = create_proc_entry("slab", 0444, proc_spl_kmem);
proc_spl_kmem_slab = proc_create_data("slab", 0444,
proc_spl_kmem, &proc_slab_operations, NULL);
if (proc_spl_kmem_slab == NULL)
SGOTO(out, rc = -EUNATCH);

proc_spl_kmem_slab->proc_fops = &proc_slab_operations;
#endif /* DEBUG_KMEM */

proc_spl_kstat = proc_mkdir("kstat", proc_spl);
Expand Down

0 comments on commit f2a745c

Please sign in to comment.