Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a58a80a authored by Alexey Dobriyan's avatar Alexey Dobriyan Committed by David S. Miller
Browse files

proc_fops: convert drivers/isdn/ to seq_file



Convert code away from ->read_proc/->write_proc interfaces.  Switch to
proc_create()/proc_create_data() which make addition of proc entries
reliable wrt NULL ->proc_fops, NULL ->data and so on.

Problem with ->read_proc et al is described here commit
786d7e16 "Fix rmmod/read/write races in
/proc entries"

[akpm@linux-foundation.org: CONFIG_PROC_FS=n build fix]
Signed-off-by: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: default avatarTilman Schmidt <tilman@imap.cc>
Signed-off-by: default avatarKarsten Keil <keil@b1-systems.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 508e14b4
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -149,10 +149,11 @@ char *(*procinfo)(struct capi_ctr *ctrlr)
	pointer to a callback function returning the entry for the device in
	the CAPI controller info table, /proc/capi/controller

read_proc_t *ctr_read_proc
	pointer to the read_proc callback function for the device's proc file
	system entry, /proc/capi/controllers/<n>; will be called with a
	pointer to the device's capi_ctr structure as the last (data) argument
const struct file_operations *proc_fops
	pointers to callback functions for the device's proc file
	system entry, /proc/capi/controllers/<n>; pointer to the device's
	capi_ctr structure is available from struct proc_dir_entry::data
	which is available from struct inode.

Note: Callback functions except send_message() are never called in interrupt
context.
+35 −64
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
@@ -1407,114 +1408,84 @@ static void capinc_tty_exit(void)
 * /proc/capi/capi20:
 *  minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
 */
static int proc_capidev_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
static int capi20_proc_show(struct seq_file *m, void *v)
{
        struct capidev *cdev;
	struct list_head *l;
	int len = 0;

	read_lock(&capidev_list_lock);
	list_for_each(l, &capidev_list) {
		cdev = list_entry(l, struct capidev, list);
		len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n",
		seq_printf(m, "0 %d %lu %lu %lu %lu\n",
			cdev->ap.applid,
			cdev->ap.nrecvctlpkt,
			cdev->ap.nrecvdatapkt,
			cdev->ap.nsentctlpkt,
			cdev->ap.nsentdatapkt);
		if (len <= off) {
			off -= len;
			len = 0;
		} else {
			if (len-off > count)
				goto endloop;
	}
	read_unlock(&capidev_list_lock);
	return 0;
}

endloop:
	read_unlock(&capidev_list_lock);
	if (len < count)
		*eof = 1;
	if (len > count) len = count;
	if (len < 0) len = 0;
	return len;
static int capi20_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, capi20_proc_show, NULL);
}

static const struct file_operations capi20_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= capi20_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

/*
 * /proc/capi/capi20ncci:
 *  applid ncci
 */
static int proc_capincci_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
static int capi20ncci_proc_show(struct seq_file *m, void *v)
{
        struct capidev *cdev;
        struct capincci *np;
	struct list_head *l;
	int len = 0;

	read_lock(&capidev_list_lock);
	list_for_each(l, &capidev_list) {
		cdev = list_entry(l, struct capidev, list);
		for (np=cdev->nccis; np; np = np->next) {
			len += sprintf(page+len, "%d 0x%x\n",
			seq_printf(m, "%d 0x%x\n",
				       cdev->ap.applid,
				       np->ncci);
			if (len <= off) {
				off -= len;
				len = 0;
			} else {
				if (len-off > count)
					goto endloop;
		}
	}
	}
endloop:
	read_unlock(&capidev_list_lock);
	*start = page+off;
	if (len < count)
		*eof = 1;
	if (len>count) len = count;
	if (len<0) len = 0;
	return len;
}

static struct procfsentries {
  char *name;
  mode_t mode;
  int (*read_proc)(char *page, char **start, off_t off,
                                       int count, int *eof, void *data);
  struct proc_dir_entry *procent;
} procfsentries[] = {
   /* { "capi",		  S_IFDIR, 0 }, */
   { "capi/capi20", 	  0	 , proc_capidev_read_proc },
   { "capi/capi20ncci",   0	 , proc_capincci_read_proc },
	return 0;
}

static int capi20ncci_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, capi20ncci_proc_show, NULL);
}

static const struct file_operations capi20ncci_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= capi20ncci_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static void __init proc_init(void)
{
    int nelem = ARRAY_SIZE(procfsentries);
    int i;

    for (i=0; i < nelem; i++) {
        struct procfsentries *p = procfsentries + i;
	p->procent = create_proc_entry(p->name, p->mode, NULL);
	if (p->procent) p->procent->read_proc = p->read_proc;
    }
	proc_create("capi/capi20", 0, NULL, &capi20_proc_fops);
	proc_create("capi/capi20ncci", 0, NULL, &capi20ncci_proc_fops);
}

static void __exit proc_exit(void)
{
    int nelem = ARRAY_SIZE(procfsentries);
    int i;

    for (i=nelem-1; i >= 0; i--) {
        struct procfsentries *p = procfsentries + i;
	if (p->procent) {
	   remove_proc_entry(p->name, NULL);
	   p->procent = NULL;
	}
    }
	remove_proc_entry("capi/capi20", NULL);
	remove_proc_entry("capi/capi20ncci", NULL);
}

/* -------- init function and module interface ---------------------- */
+17 −38
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/isdn.h>
#include <linux/isdnif.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/ctype.h>
@@ -2229,59 +2230,37 @@ static void lower_callback(unsigned int cmd, u32 contr, void *data)
 * /proc/capi/capidrv:
 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
 */
static int proc_capidrv_read_proc(char *page, char **start, off_t off,
                                       int count, int *eof, void *data)
static int capidrv_proc_show(struct seq_file *m, void *v)
{
	int len = 0;

	len += sprintf(page+len, "%lu %lu %lu %lu\n",
	seq_printf(m, "%lu %lu %lu %lu\n",
			global.ap.nrecvctlpkt,
			global.ap.nrecvdatapkt,
			global.ap.nsentctlpkt,
			global.ap.nsentdatapkt);
	if (off+count >= len)
	   *eof = 1;
	if (len < off)
	return 0;
	*start = page + off;
	return ((count < len-off) ? count : len-off);
}

static struct procfsentries {
  char *name;
  mode_t mode;
  int (*read_proc)(char *page, char **start, off_t off,
                                       int count, int *eof, void *data);
  struct proc_dir_entry *procent;
} procfsentries[] = {
   /* { "capi",		  S_IFDIR, 0 }, */
   { "capi/capidrv", 	  0	 , proc_capidrv_read_proc },
}

static int capidrv_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, capidrv_proc_show, NULL);
}

static const struct file_operations capidrv_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= capidrv_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static void __init proc_init(void)
{
    int nelem = ARRAY_SIZE(procfsentries);
    int i;

    for (i=0; i < nelem; i++) {
        struct procfsentries *p = procfsentries + i;
	p->procent = create_proc_entry(p->name, p->mode, NULL);
	if (p->procent) p->procent->read_proc = p->read_proc;
    }
	proc_create("capi/capidrv", 0, NULL, &capidrv_proc_fops);
}

static void __exit proc_exit(void)
{
    int nelem = ARRAY_SIZE(procfsentries);
    int i;

    for (i=nelem-1; i >= 0; i--) {
        struct procfsentries *p = procfsentries + i;
	if (p->procent) {
	   remove_proc_entry(p->name, NULL);
	   p->procent = NULL;
	}
    }
	remove_proc_entry("capi/capidrv", NULL);
}

static int __init capidrv_init(void)
+1 −7
Original line number Diff line number Diff line
@@ -490,13 +490,7 @@ attach_capi_ctr(struct capi_ctr *card)
	card->traceflag = showcapimsgs;

	sprintf(card->procfn, "capi/controllers/%d", card->cnr);
	card->procent = create_proc_entry(card->procfn, 0, NULL);
	if (card->procent) {
	   card->procent->read_proc = 
		(int (*)(char *,char **,off_t,int,int *,void *))
			card->ctr_read_proc;
	   card->procent->data = card;
	}
	card->procent = proc_create_data(card->procfn, 0, NULL, card->proc_fops, card);

	ncards++;
	printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n",
+36 −39
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@

#include "gigaset.h"
#include <linux/ctype.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/isdn/capilli.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
@@ -2106,35 +2108,22 @@ static char *gigaset_procinfo(struct capi_ctr *ctr)
	return ctr->name;	/* ToDo: more? */
}

/**
 * gigaset_ctr_read_proc() - build controller proc file entry
 * @page:	buffer of PAGE_SIZE bytes for receiving the entry.
 * @start:	unused.
 * @off:	unused.
 * @count:	unused.
 * @eof:	unused.
 * @ctr:	controller descriptor structure.
 *
 * Return value: length of generated entry
 */
static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
			  int count, int *eof, struct capi_ctr *ctr)
static int gigaset_proc_show(struct seq_file *m, void *v)
{
	struct capi_ctr *ctr = m->private;
	struct cardstate *cs = ctr->driverdata;
	char *s;
	int i;
	int len = 0;
	len += sprintf(page+len, "%-16s %s\n", "name", ctr->name);
	len += sprintf(page+len, "%-16s %s %s\n", "dev",

	seq_printf(m, "%-16s %s\n", "name", ctr->name);
	seq_printf(m, "%-16s %s %s\n", "dev",
			dev_driver_string(cs->dev), dev_name(cs->dev));
	len += sprintf(page+len, "%-16s %d\n", "id", cs->myid);
	seq_printf(m, "%-16s %d\n", "id", cs->myid);
	if (cs->gotfwver)
		len += sprintf(page+len, "%-16s %d.%d.%d.%d\n", "firmware",
		seq_printf(m, "%-16s %d.%d.%d.%d\n", "firmware",
			cs->fwver[0], cs->fwver[1], cs->fwver[2], cs->fwver[3]);
	len += sprintf(page+len, "%-16s %d\n", "channels",
			cs->channels);
	len += sprintf(page+len, "%-16s %s\n", "onechannel",
			cs->onechannel ? "yes" : "no");
	seq_printf(m, "%-16s %d\n", "channels", cs->channels);
	seq_printf(m, "%-16s %s\n", "onechannel", cs->onechannel ? "yes" : "no");

	switch (cs->mode) {
	case M_UNKNOWN:
@@ -2152,7 +2141,7 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
	default:
		s = "??";
	}
	len += sprintf(page+len, "%-16s %s\n", "mode", s);
	seq_printf(m, "%-16s %s\n", "mode", s);

	switch (cs->mstate) {
	case MS_UNINITIALIZED:
@@ -2176,25 +2165,21 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
	default:
		s = "??";
	}
	len += sprintf(page+len, "%-16s %s\n", "mstate", s);
	seq_printf(m, "%-16s %s\n", "mstate", s);

	len += sprintf(page+len, "%-16s %s\n", "running",
			cs->running ? "yes" : "no");
	len += sprintf(page+len, "%-16s %s\n", "connected",
			cs->connected ? "yes" : "no");
	len += sprintf(page+len, "%-16s %s\n", "isdn_up",
			cs->isdn_up ? "yes" : "no");
	len += sprintf(page+len, "%-16s %s\n", "cidmode",
			cs->cidmode ? "yes" : "no");
	seq_printf(m, "%-16s %s\n", "running", cs->running ? "yes" : "no");
	seq_printf(m, "%-16s %s\n", "connected", cs->connected ? "yes" : "no");
	seq_printf(m, "%-16s %s\n", "isdn_up", cs->isdn_up ? "yes" : "no");
	seq_printf(m, "%-16s %s\n", "cidmode", cs->cidmode ? "yes" : "no");

	for (i = 0; i < cs->channels; i++) {
		len += sprintf(page+len, "[%d]%-13s %d\n", i, "corrupted",
		seq_printf(m, "[%d]%-13s %d\n", i, "corrupted",
				cs->bcs[i].corrupted);
		len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_down",
		seq_printf(m, "[%d]%-13s %d\n", i, "trans_down",
				cs->bcs[i].trans_down);
		len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_up",
		seq_printf(m, "[%d]%-13s %d\n", i, "trans_up",
				cs->bcs[i].trans_up);
		len += sprintf(page+len, "[%d]%-13s %d\n", i, "chstate",
		seq_printf(m, "[%d]%-13s %d\n", i, "chstate",
				cs->bcs[i].chstate);
		switch (cs->bcs[i].proto2) {
		case L2_BITSYNC:
@@ -2209,11 +2194,23 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
		default:
			s = "??";
		}
		len += sprintf(page+len, "[%d]%-13s %s\n", i, "proto2", s);
		seq_printf(m, "[%d]%-13s %s\n", i, "proto2", s);
	}
	return len;
	return 0;
}

static int gigaset_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, gigaset_proc_show, PDE(inode)->data);
}

static const struct file_operations gigaset_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= gigaset_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static struct capi_driver capi_driver_gigaset = {
	.name		= "gigaset",
@@ -2256,7 +2253,7 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
	iif->ctr.release_appl  = gigaset_release_appl;
	iif->ctr.send_message  = gigaset_send_message;
	iif->ctr.procinfo      = gigaset_procinfo;
	iif->ctr.ctr_read_proc = gigaset_ctr_read_proc;
	iif->ctr.proc_fops = &gigaset_proc_fops;
	INIT_LIST_HEAD(&iif->appls);
	skb_queue_head_init(&iif->sendqueue);
	atomic_set(&iif->sendqlen, 0);
Loading