From 640987e4ca9aa3cb59fb67302b6055b3b739f2f1 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 24 Mar 2003 22:09:17 +0000 Subject: [AGPGART] New PCI idents for new VIA GARTs --- include/linux/pci_ids.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3e1f5a319034..af8573498b0a 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1070,6 +1070,7 @@ #define PCI_DEVICE_ID_TTI_HPT374 0x0008 #define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_DEVICE_ID_VIA_P4X600 0x0198 #define PCI_DEVICE_ID_VIA_8363_0 0x0305 #define PCI_DEVICE_ID_VIA_8371_0 0x0391 #define PCI_DEVICE_ID_VIA_8501_0 0x0501 @@ -1109,11 +1110,19 @@ #define PCI_DEVICE_ID_VIA_8653_0 0x3101 #define PCI_DEVICE_ID_VIA_8622 0x3102 #define PCI_DEVICE_ID_VIA_8233C_0 0x3109 -#define PCI_DEVICE_ID_VIA_8361 0x3112 +#define PCI_DEVICE_ID_VIA_8361 0x3112 +#define PCI_DEVICE_ID_VIA_KM266 0x3116 +#define PCI_DEVICE_ID_VIA_CLE266 0x3123 +#define PCI_DEVICE_ID_VIA_8753_0 0x3128 #define PCI_DEVICE_ID_VIA_8233A 0x3147 +#define PCI_DEVICE_ID_VIA_8752 0x3148 +#define PCI_DEVICE_ID_VIA_KN266 0x3156 #define PCI_DEVICE_ID_VIA_8754 0x3168 #define PCI_DEVICE_ID_VIA_8235 0x3177 +#define PCI_DEVICE_ID_VIA_P4N333 0x3178 #define PCI_DEVICE_ID_VIA_8377_0 0x3189 +#define PCI_DEVICE_ID_VIA_KM400 0x3205 +#define PCI_DEVICE_ID_VIA_P4M400 0x3209 #define PCI_DEVICE_ID_VIA_86C100A 0x6100 #define PCI_DEVICE_ID_VIA_8231 0x8231 #define PCI_DEVICE_ID_VIA_8231_4 0x8235 -- cgit v1.2.3 From abe5d153a034a1b62c49340ac5cdca33b26717c5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 6 Apr 2003 04:07:58 -0300 Subject: o linux/net.h: prune the include dependency tree, remove include socket.h Use struct forward declaration and fix irda.h and netlink.h to include what uses (only sa_family_t). --- include/linux/irda.h | 2 ++ include/linux/net.h | 5 ++++- include/linux/netlink.h | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/irda.h b/include/linux/irda.h index bdf23baa5483..948488ece2a8 100644 --- a/include/linux/irda.h +++ b/include/linux/irda.h @@ -25,6 +25,8 @@ #ifndef KERNEL_IRDA_H #define KERNEL_IRDA_H +#include /* only for sa_family_t */ + /* Hint bit positions for first hint byte */ #define HINT_PNP 0x01 #define HINT_PDA 0x02 diff --git a/include/linux/net.h b/include/linux/net.h index 55083c938298..6ba6e1038521 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -19,7 +19,6 @@ #define _LINUX_NET_H #include -#include #include struct poll_table_struct; @@ -88,6 +87,8 @@ struct socket { struct vm_area_struct; struct page; struct kiocb; +struct sockaddr; +struct msghdr; struct proto_ops { int family; @@ -136,6 +137,8 @@ struct net_proto_family { short encrypt_net; }; +struct iovec; + extern int sock_wake_async(struct socket *sk, int how, int band); extern int sock_register(struct net_proto_family *fam); extern int sock_unregister(int family); diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 69346c394563..30de192de7a9 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -1,6 +1,8 @@ #ifndef __LINUX_NETLINK_H #define __LINUX_NETLINK_H +#include /* for sa_family_t */ + #define NETLINK_ROUTE 0 /* Routing/device hook */ #define NETLINK_SKIP 1 /* Reserved for ENskip */ #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ -- cgit v1.2.3 From ecca22ec87ff5ede894ac4674b5196d1c613d33c Mon Sep 17 00:00:00 2001 From: Zwane Mwaikambo Date: Sun, 6 Apr 2003 05:21:24 -0700 Subject: [PATCH] Grab SET_MODULE_OWNER from the clutches of the deprecated This comment seems to want to include SET_MODULE_OWNER as one of the deprecated facilities. --- include/linux/module.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/module.h b/include/linux/module.h index 30892e436401..657802c8af75 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -408,9 +408,9 @@ __attribute__((section(".gnu.linkonce.this_module"))) = { #endif /* MODULE */ #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x) +#define SET_MODULE_OWNER(dev) ((dev)->owner = THIS_MODULE) /* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */ -#define SET_MODULE_OWNER(dev) ((dev)->owner = THIS_MODULE) struct obsolete_modparm { char name[64]; -- cgit v1.2.3 From 68132d898b0a59334b55e95f646173f6efc3e75b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sun, 6 Apr 2003 18:29:36 -0700 Subject: [PATCH] kill blk_queue_empty() This finally kills of blk_queue_empty(). This is similar to the patch I recently sent to fix the SCSI logic as well. A lot of drivers are doing this in our core, mainly because that is the way they always did it: start_queue: if (blk_queue_empty(q)) return; rq = elv_next_request(q); if (!rq) return; Patch simply removes the blk_queue_empty() check, and adds a check for !rq return from elv_next_request() if the driver didn't already do that. Additionally, the AS io scheduler can return NULL from elv_next_request() if it thinks this is best. This way we are also prepared for that to work well. Patch was done by Nick Piggin. --- arch/m68k/atari/stram.c | 5 +++-- drivers/acorn/block/fd1772.c | 6 +++--- drivers/acorn/block/mfmhd.c | 6 +++--- drivers/block/DAC960.c | 6 +++--- drivers/block/acsi.c | 6 +++--- drivers/block/amiflop.c | 2 +- drivers/block/ataflop.c | 8 ++++---- drivers/block/cciss.c | 4 ++-- drivers/block/cpqarray.c | 4 ++-- drivers/block/ll_rw_blk.c | 2 +- drivers/block/nbd.c | 6 +++--- drivers/block/paride/pcd.c | 5 +++-- drivers/block/paride/pd.c | 4 ++-- drivers/block/ps2esdi.c | 7 ++----- drivers/block/swim3.c | 4 ++-- drivers/block/swim_iop.c | 2 +- drivers/block/xd.c | 5 +++-- drivers/block/z2ram.c | 4 ++-- drivers/cdrom/aztcd.c | 2 +- drivers/cdrom/cdu31a.c | 4 ++-- drivers/cdrom/cm206.c | 4 ++-- drivers/cdrom/gscd.c | 4 ++-- drivers/cdrom/mcd.c | 2 +- drivers/cdrom/mcdx.c | 4 ++-- drivers/cdrom/optcd.c | 2 +- drivers/cdrom/sbpcd.c | 11 ++++++----- drivers/cdrom/sjcd.c | 2 +- drivers/cdrom/sonycd535.c | 4 ++-- drivers/ide/ide-io.c | 3 ++- drivers/ide/legacy/hd.c | 16 ++++++++-------- drivers/ide/legacy/hd98.c | 12 ++++++------ drivers/message/i2o/i2o_block.c | 4 +--- drivers/mtd/ftl.c | 4 ++-- drivers/mtd/mtdblock.c | 6 +++--- drivers/mtd/mtdblock_ro.c | 5 +++-- drivers/mtd/nftlcore.c | 5 +++-- drivers/s390/block/dasd.c | 2 +- drivers/s390/char/tape_block.c | 8 ++++---- drivers/sbus/char/jsflash.c | 5 +++-- drivers/scsi/scsi_lib.c | 10 +++++----- include/linux/blkdev.h | 1 - 41 files changed, 104 insertions(+), 102 deletions(-) (limited to 'include/linux') diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index 7868a499d8e4..f09dd0321e84 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -976,8 +976,9 @@ static int refcnt = 0; static void do_stram_request(request_queue_t *q) { - while (!blk_queue_empty(q)) { - struct request *req = elv_next_request(q); + struct request *req; + + while ((req = elv_next_request(q)) != NULL) { void *start = swap_start + (req->sector << 9); unsigned long len = req->current_nr_sectors << 9; if ((start + len) > swap_end) { diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index 2a344695c35b..6104ea2e254c 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c @@ -598,7 +598,7 @@ static void fd_error(void) { printk("FDC1772: fd_error\n"); /*panic("fd1772: fd_error"); *//* DAG tmp */ - if (blk_queue_empty(QUEUE)) + if (!CURRENT) return; CURRENT->errors++; if (CURRENT->errors >= MAX_ERRORS) { @@ -1207,11 +1207,11 @@ static void redo_fd_request(void) DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n", CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "", - !blk_queue_empty(QUEUE) ? CURRENT->sector : 0)); + CURRENT ? CURRENT->sector : 0)); repeat: - if (blk_queue_empty(QUEUE)) + if (!CURRENT) goto the_end; floppy = CURRENT->rq_disk->private_data; diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 172b48006da3..dbd0da7492fa 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -746,7 +746,7 @@ static void request_done(int uptodate) /* No - its the end of the line */ /* end_request's should have happened at the end of sector DMAs */ /* Turns Drive LEDs off - may slow it down? */ - if (blk_queue_empty(QUEUE)) + if (!elv_next_request(QUEUE)) issue_command(CMD_CKV, block, 2); Busy = 0; @@ -897,9 +897,9 @@ static void mfm_request(void) DBG("mfm_request: loop start\n"); sti(); - DBG("mfm_request: before blk_queue_empty\n"); + DBG("mfm_request: before !CURRENT\n"); - if (blk_queue_empty(QUEUE)) { + if (!CURRENT) { printk("mfm_request: Exiting due to empty queue (pre)\n"); do_mfm = NULL; Busy = 0; diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index ecad76d1065b..9362b6cb01eb 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -3181,10 +3181,10 @@ static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller, return false; while (true) { - if (blk_queue_empty(RequestQueue)) - return false; - Request = elv_next_request(RequestQueue); + if (!Request) + return false; + Command = DAC960_AllocateCommand(Controller); if (Command != NULL) break; diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index ea581f6547d4..02651681338b 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -763,7 +763,7 @@ static void unexpected_acsi_interrupt( void ) static void bad_rw_intr( void ) { - if (blk_queue_empty(QUEUE)) + if (!CURRENT) return; if (++CURRENT->errors >= MAX_ERRORS) @@ -837,7 +837,7 @@ static void acsi_times_out( unsigned long dummy ) do_acsi = NULL; printk( KERN_ERR "ACSI timeout\n" ); - if (blk_queue_empty(QUEUE)) + if (!CURRENT) return; if (++CURRENT->errors >= MAX_ERRORS) { #ifdef DEBUG @@ -956,7 +956,7 @@ static void redo_acsi_request( void ) if (do_acsi) return; - if (blk_queue_empty(QUEUE)) { + if (!CURRENT) { do_acsi = NULL; ENABLE_IRQ(); stdma_release(); diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index b473e3b08ce1..a1b73f1a12c5 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1365,7 +1365,7 @@ static void redo_fd_request(void) unsigned long flags; repeat: - if (blk_queue_empty(QUEUE)) { + if (!CURRENT) { /* Nothing left to do */ return; } diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index f0f36de7fcda..23249c0c1161 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -627,7 +627,7 @@ static void fd_error( void ) return; } - if (blk_queue_empty(QUEUE)) + if (!CURRENT) return; CURRENT->errors++; @@ -1435,14 +1435,14 @@ static void redo_fd_request(void) struct atari_floppy_struct *floppy; DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n", - CURRENT, !blk_queue_empty(QUEUE) ? CURRENT->rq_disk->disk_name : "", - !blk_queue_empty(QUEUE) ? CURRENT->sector : 0 )); + CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "", + CURRENT ? CURRENT->sector : 0 )); IsFormatting = 0; repeat: - if (blk_queue_empty(QUEUE)) + if (!CURRENT) goto the_end; floppy = CURRENT->rq_disk->private_data; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d69451c16c20..8987b67272cd 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1876,10 +1876,10 @@ static void do_cciss_request(request_queue_t *q) goto startio; queue: - if (blk_queue_empty(q)) + creq = elv_next_request(q); + if (!creq) goto startio; - creq = elv_next_request(q); if (creq->nr_phys_segments > MAXSGENTRIES) BUG(); diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 91ed5814471f..f4dfe8761982 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -786,10 +786,10 @@ static void do_ida_request(request_queue_t *q) goto startio; queue_next: - if (blk_queue_empty(q)) + creq = elv_next_request(q); + if (!creq) goto startio; - creq = elv_next_request(q); if (creq->nr_phys_segments > SG_MAX) BUG(); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 5ed2f6882f6d..e14210308577 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1698,7 +1698,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) again: insert_here = NULL; - if (blk_queue_empty(q)) { + if (elv_queue_empty(q)) { blk_plug_device(q); goto get_rq; } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index c13ff60956c0..ee5f51284419 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -337,9 +337,9 @@ void nbd_clear_que(struct nbd_device *lo) static void do_nbd_request(request_queue_t * q) { - - while (!blk_queue_empty(q)) { - struct request *req = elv_next_request(q); + struct request *req; + + while ((req = elv_next_request(q)) != NULL) { struct nbd_device *lo; if (!(req->flags & REQ_CMD)) diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 4e2335b6fc72..1f64202835b7 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -739,9 +739,10 @@ static void do_pcd_request(request_queue_t * q) if (pcd_busy) return; while (1) { - if (blk_queue_empty(q)) - return; pcd_req = elv_next_request(q); + if (!pcd_req) + return; + if (rq_data_dir(pcd_req) == READ) { struct pcd_unit *cd = pcd_req->rq_disk->private_data; if (cd != pcd_current) diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 144c42fbca50..a347c67c1eae 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -726,10 +726,10 @@ static void do_pd_request(request_queue_t * q) if (pd_busy) return; repeat: - if (blk_queue_empty(q)) + pd_req = elv_next_request(q); + if (!pd_req) return; - pd_req = elv_next_request(q); pd_block = pd_req->sector; pd_run = pd_req->nr_sectors; pd_count = pd_req->current_nr_sectors; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index b71b02fabdf1..1d46f052d109 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -477,12 +477,9 @@ static void do_ps2esdi_request(request_queue_t * q) /* since, this routine is called with interrupts cleared - they must be before it finishes */ - /* standard procedure to ensure that requests are really on the - list + sanity checks. */ - if (blk_queue_empty(q)) - return; - req = elv_next_request(q); + if (!req) + return; #if 0 printk("%s:got request. device : %s command : %d sector : %ld count : %ld, buffer: %p\n", diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 0b652196606f..0348b5330f8d 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -305,6 +305,7 @@ static void do_fd_request(request_queue_t * q) static void start_request(struct floppy_state *fs) { + struct request *req; unsigned long x; if (fs->state == idle && fs->wanted) { @@ -312,8 +313,7 @@ static void start_request(struct floppy_state *fs) wake_up(&fs->wait); return; } - while (!blk_queue_empty(&swim3_queue) && fs->state == idle) { - struct request *req = elv_next_request(&swim3_queue); + while (fs->state == idle && (req = elv_next_request(&swim3_queue))) { #if 0 printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n", req->rq_disk->disk_name, req->cmd, diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c index e96d4362b24c..958a333bb29f 100644 --- a/drivers/block/swim_iop.c +++ b/drivers/block/swim_iop.c @@ -516,7 +516,7 @@ static void start_request(struct floppy_state *fs) wake_up(&fs->wait); return; } - while (!blk_queue_empty(&swim_queue) && fs->state == idle) { + while (CURRENT && fs->state == idle) { if (CURRENT->bh && !buffer_locked(CURRENT->bh)) panic("floppy: block not locked"); #if 0 diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 1da1122dc898..206e3247c81e 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -282,11 +282,12 @@ static u_char __init xd_detect (u_char *controller, unsigned int *address) /* do_xd_request: handle an incoming request */ static void do_xd_request (request_queue_t * q) { + struct request *req; + if (xdc_busy) return; - while (!blk_queue_empty(q)) { - struct request *req = elv_next_request(q); + while ((req = elv_next_request(q)) != NULL) { unsigned block = req->sector; unsigned count = req->nr_sectors; int rw = rq_data_dir(req); diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index cac3ee05bfb0..a9b95fb8eef3 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -73,8 +73,8 @@ static struct gendisk *z2ram_gendisk; static void do_z2_request(request_queue_t *q) { - while (!blk_queue_empty(q)) { - struct request *req = elv_next_request(q); + struct request *req; + while ((req = elv_next_request) != NULL) { unsigned long start = req->sector << 9; unsigned long len = req->current_nr_sectors << 9; diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index 0171a9ea0b40..287904f314ca 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -231,7 +231,7 @@ static struct request_queue azt_queue; static int current_valid(void) { - return !blk_queue_empty(QUEUE) && + return CURRENT && CURRENT->cmd == READ && CURRENT->sector != -1; } diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index 915afe6dfe71..a6b49cacd3f3 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -1583,13 +1583,13 @@ static void do_cdu31a_request(request_queue_t * q) * The beginning here is stolen from the hard disk driver. I hope * it's right. */ - if (blk_queue_empty(q)) + req = elv_next_request(q); + if (!req) goto end_do_cdu31a_request; if (!sony_spun_up) scd_spinup(); - req = elv_next_request(q); block = req->sector; nblock = req->nr_sectors; diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index 3fb0301e028d..a91a5f1baf08 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -855,10 +855,10 @@ static void do_cm206_request(request_queue_t * q) struct request *req; while (1) { /* repeat until all requests have been satisfied */ - if (blk_queue_empty(q)) + req = elv_next_request(q); + if (!req) return; - req = elv_next_request(q); if (req->cmd != READ) { debug(("Non-read command %d on cdrom\n", req->cmd)); end_request(req, 0); diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index 209e5c2eb516..feb97de4e8de 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -257,10 +257,10 @@ static void __do_gscd_request(unsigned long dummy) unsigned int nsect; repeat: - if (blk_queue_empty(&gscd_queue)) + req = elv_next_request(&gscd_queue); + if (!req) return; - req = elv_next_request(&gscd_queue); block = req->sector; nsect = req->nr_sectors; diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c index 48cbb70d3ccf..9fc28c028df7 100644 --- a/drivers/cdrom/mcd.c +++ b/drivers/cdrom/mcd.c @@ -125,7 +125,7 @@ static struct request_queue mcd_queue; static int current_valid(void) { - return !blk_queue_empty(QUEUE) && + return CURRENT && CURRENT->cmd == READ && CURRENT->sector != -1; } diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index 8abd7a0de311..9e125e05a146 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -582,10 +582,10 @@ void do_mcdx_request(request_queue_t * q) again: - if (blk_queue_empty(q)) + req = elv_next_request(q); + if (!req) return; - req = elv_next_request(q); stuffp = req->rq_disk->private_data; if (!stuffp->present) { diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 874677d8fc81..ff13737af509 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -977,7 +977,7 @@ static int update_toc(void) static int current_valid(void) { - return !blk_queue_empty(QUEUE) && + return CURRENT && CURRENT->cmd == READ && CURRENT->sector != -1; } diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index ae6787aba3db..6ecf532d670e 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -4852,7 +4852,9 @@ static void do_sbpcd_request(request_queue_t * q) #ifdef DEBUG_GTL xnr=++xx_nr; - if(blk_queue_empty(q)) + req = elv_next_request(q); + + if (!req) { printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n", xnr, current->pid, jiffies); @@ -4861,15 +4863,14 @@ static void do_sbpcd_request(request_queue_t * q) return; } - req = elv_next_request(q); - printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n", xnr, req, req->sector, req->nr_sectors, current->pid, jiffies); #endif - if (blk_queue_empty(q)) + + req = elv_next_request(q); /* take out our request so no other */ + if (!req) return; - req = elv_next_request(q); /* take out our request so no other */ if (req -> sector == -1) end_request(req, 0); spin_unlock_irq(q->queue_lock); diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index 63e909879b9f..db131a108795 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -1064,7 +1064,7 @@ static void sjcd_invalidate_buffers(void) static int current_valid(void) { - return !blk_queue_empty(QUEUE) && + return CURRENT && CURRENT->cmd == READ && CURRENT->sector != -1; } diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c index 4a5730de8af6..4cb25c3c4d68 100644 --- a/drivers/cdrom/sonycd535.c +++ b/drivers/cdrom/sonycd535.c @@ -797,10 +797,10 @@ do_cdu535_request(request_queue_t * q) Byte cmd[2]; while (1) { - if (blk_queue_empty(q)) + req = elv_next_request(q); + if (!req) return; - req = elv_next_request(q); block = req->sector; nsect = req->nr_sectors; if (!(req->flags & REQ_CMD)) diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index ea84e881e2ba..d04637085070 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -673,7 +673,8 @@ repeat: best = NULL; drive = hwgroup->drive; do { - if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) { + if ((!drive->sleep || time_after_eq(jiffies, drive->sleep)) + && !elv_queue_empty(&drive->queue)) { if (!best || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index d4e6dbbb929b..8946722f9115 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -194,7 +194,7 @@ void __init hd_setup(char *str, int *ints) static void dump_status (const char *msg, unsigned int stat) { char *name = "hd?"; - if (!blk_queue_empty(QUEUE)) + if (CURRENT) name = CURRENT->rq_disk->disk_name; #ifdef VERBOSE_ERRORS @@ -223,7 +223,7 @@ static void dump_status (const char *msg, unsigned int stat) if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL), inb(HD_CURRENT) & 0xf, inb(HD_SECTOR)); - if (!blk_queue_empty(QUEUE)) + if (CURRENT) printk(", sector=%ld", CURRENT->sector); } printk("\n"); @@ -403,8 +403,8 @@ void unexpected_hd_interrupt(void) */ static void bad_rw_intr(void) { - if (!blk_queue_empty(QUEUE)) { - struct request *req = CURRENT; + struct request *req = CURRENT; + if (req != NULL) { struct hd_i_struct *disk = req->rq_disk->private_data; if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { end_request(req, 0); @@ -469,7 +469,7 @@ ok_to_read: #if (HD_DELAY > 0) last_req = read_timer(); #endif - if (!blk_queue_empty(QUEUE)) + if (elv_next_request(QUEUE)) hd_request(); return; } @@ -532,7 +532,7 @@ static void hd_times_out(unsigned long dummy) do_hd = NULL; - if (blk_queue_empty(QUEUE)) + if (!CURRENT) return; disable_irq(HD_IRQ); @@ -588,11 +588,11 @@ repeat: del_timer(&device_timer); local_irq_enable(); - if (blk_queue_empty(QUEUE)) { + req = CURRENT; + if (!req) { do_hd = NULL; return; } - req = CURRENT; if (reset) { local_irq_disable(); diff --git a/drivers/ide/legacy/hd98.c b/drivers/ide/legacy/hd98.c index a5128619f972..c7b61ac8424b 100644 --- a/drivers/ide/legacy/hd98.c +++ b/drivers/ide/legacy/hd98.c @@ -197,7 +197,7 @@ static void dump_status (const char *msg, unsigned int stat) { char devc; - devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?'; + devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?'; #ifdef VERBOSE_ERRORS printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff); if (stat & BUSY_STAT) printk("Busy "); @@ -224,7 +224,7 @@ static void dump_status (const char *msg, unsigned int stat) if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL), inb(HD_CURRENT) & 0xf, inb(HD_SECTOR)); - if (!blk_queue_empty(QUEUE)) + if (CURRENT) printk(", sector=%ld", CURRENT->sector); } printk("\n"); @@ -400,7 +400,7 @@ static void bad_rw_intr(void) { int dev; - if (blk_queue_empty(QUEUE)) + if (!CURRENT) return; dev = DEVICE_NR(CURRENT->rq_dev); if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { @@ -463,7 +463,7 @@ ok_to_read: #if (HD_DELAY > 0) last_req = read_timer(); #endif - if (!blk_queue_empty(QUEUE)) + if (CURRENT) hd_request(); return; } @@ -525,7 +525,7 @@ static void hd_times_out(unsigned long dummy) do_hd = NULL; - if (blk_queue_empty(QUEUE)) + if (!CURRENT) return; disable_irq(HD_IRQ); @@ -579,7 +579,7 @@ repeat: del_timer(&device_timer); local_irq_enable(); - if (blk_queue_empty(QUEUE)) { + if (!CURRENT) { do_hd = NULL; return; } diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 9fb7a5dd8b5e..6e812217afa8 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -783,14 +783,12 @@ static void i2ob_request(request_queue_t *q) struct i2ob_device *dev; u32 m; - while (blk_queue_empty(q)) { + while ((req = elv_next_request(q)) != NULL) { /* * On an IRQ completion if there is an inactive * request on the queue head it means it isnt yet * ready to dispatch. */ - req = elv_next_request(q); - if(req->rq_status == RQ_INACTIVE) return; diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index fa7ab618f07f..fa49bd7d4511 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1135,9 +1135,9 @@ static void do_ftl_request(struct request_queue *q) do { // sti(); - if (blk_queue_empty(q)) - return; req = elv_next_request(q); + if (!req) + return; part = req->rq_disk->private_data; if (part) { ret = 0; diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 9883a8ea890f..34bcc7a56e4a 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -384,11 +384,11 @@ static release_t mtdblock_release(struct inode *inode, struct file *file) static struct request_queue mtd_queue; static void handle_mtdblock_request(void) { + struct request *req; struct mtdblk_dev *mtdblk; unsigned int res; - while (!blk_queue_empty(&mtd_queue)) { - struct request *req = elv_next_request(&mtd_queue); + while ((req = elv_next_request(&mtd_queue) != NULL) { struct mtdblk_dev **p = req->rq_disk->private_data; spin_unlock_irq(mtd_queue.queue_lock); mtdblk = *p; @@ -458,7 +458,7 @@ int mtdblock_thread(void *dummy) add_wait_queue(&thr_wq, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irq(mtd_queue.queue_lock); - if (blk_queue_empty(&mtd_queue) || blk_queue_plugged(&mtd_queue)) { + if (!elv_next_request(&mtd_queue) || blk_queue_plugged(&mtd_queue)) { spin_unlock_irq(mtd_queue.queue_lock); schedule(); remove_wait_queue(&thr_wq, &wait); diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index 950d2f5650da..3083f0c41a06 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -93,8 +93,9 @@ static release_t mtdblock_release(struct inode *inode, struct file *file) static void mtdblock_request(request_queue_t *q) { - while (!blk_queue_empty(q)) { - struct request *req = elv_next_request(q); + struct request *req; + + while ((req = elv_next_request(q)) != NULL) { struct mtdro_dev *mdev = req->rq_disk->private_data; struct mtd_info *mtd = mdev->mtd; unsigned int res; diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 1b99e2a0c070..7e9414f6263e 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -780,8 +780,9 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd void nftl_request(struct request_queue *q) { - while (!blk_queue_empty(q)) { - struct request *req = elv_next_request(q); + struct request *req; + + while ((req = elv_next_request(q)) != NULL) { unsigned block = req->sector; unsigned nsect = req->current_nr_sectors; char *buffer = req->buffer; diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4a341097e10f..204383e5b37a 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1217,7 +1217,7 @@ __dasd_process_blk_queue(dasd_device_t * device) nr_queued++; } while (!blk_queue_plugged(queue) && - !blk_queue_empty(queue) && + elv_next_request(queue) && nr_queued < DASD_CHANQ_MAX_SIZE) { req = elv_next_request(queue); if (device->ro_flag && rq_data_dir(req) == WRITE) { diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 6731a38d82be..8bdb1a9f891f 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -69,7 +69,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) device->blk_data.block_position = -1; device->discipline->free_bread(ccw_req); if (!list_empty(&device->req_queue) || - !blk_queue_empty(&device->blk_data.request_queue)) + elv_next_request(&device->blk_data.request_queue)) tasklet_schedule(&device->blk_data.tasklet); } @@ -95,7 +95,7 @@ __tape_process_blk_queue(struct tape_device *device, struct list_head *new_req) list_for_each(l, &device->req_queue) nr_queued++; while (!blk_queue_plugged(queue) && - !blk_queue_empty(queue) && + elv_next_request(queue) && nr_queued < TAPEBLOCK_MIN_REQUEUE) { req = elv_next_request(queue); if (rq_data_dir(req) == WRITE) { @@ -162,7 +162,7 @@ tapeblock_request_fn(request_queue_t *queue) struct tape_device *device; device = (struct tape_device *) queue->queuedata; - while (!blk_queue_empty(queue)) { + while (elv_next_request(queue)) { INIT_LIST_HEAD(&new_req); spin_lock(get_ccwdev_lock(device->cdev)); __tape_process_blk_queue(device, &new_req); @@ -187,7 +187,7 @@ tapeblock_tasklet(unsigned long data) struct tape_device *device; device = (struct tape_device *) data; - while (!blk_queue_empty(&device->blk_data.request_queue)) { + while (elv_next_request(&device->blk_data.request_queue)) { INIT_LIST_HEAD(&new_req); spin_lock_irq(get_ccwdev_lock(device->cdev)); __tape_process_blk_queue(device, &new_req); diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 81cdfbfa47b1..7d477c0d01a1 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -190,8 +190,9 @@ static void jsfd_read(char *buf, unsigned long p, size_t togo) { static void jsfd_do_request(request_queue_t *q) { - while (!blk_queue_empty(q)) { - struct request *req = elv_next_request(q); + struct request *req; + + while ((req = elv_next_request(q)) != NULL) { struct jsfd_part *jdp = req->rq_disk->private_data; unsigned long offset = req->sector << 9; size_t len = req->current_nr_sectors << 9; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index a6694681aa6d..986c27c43268 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -398,14 +398,14 @@ static void scsi_queue_next_request(request_queue_t *q, struct scsi_cmnd *cmd) * with special case code, then spin off separate versions and * use function pointers to pick the right one. */ - if (sdev->single_lun && blk_queue_empty(q) && sdev->device_busy ==0 && - !shost->host_blocked && !shost->host_self_blocked && - !((shost->can_queue > 0) && (shost->host_busy >= - shost->can_queue))) { + if (sdev->single_lun && sdev->device_busy == 0 && + !shost->host_blocked && !shost->host_self_blocked && + !((shost->can_queue > 0) && (shost->host_busy >= shost->can_queue)) + && elv_queue_empty(q)) { list_for_each_entry(sdev2, &sdev->same_target_siblings, same_target_siblings) { if (!sdev2->device_blocked && - !blk_queue_empty(sdev2->request_queue)) { + !elv_queue_empty(sdev2->request_queue)) { __blk_run_queue(sdev2->request_queue); break; } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index b5a2f676c4f8..ee3f66a5e60c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -260,7 +260,6 @@ struct request_queue #define blk_queue_plugged(q) !list_empty(&(q)->plug_list) #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) -#define blk_queue_empty(q) elv_queue_empty(q) #define blk_fs_request(rq) ((rq)->flags & REQ_CMD) #define blk_pc_request(rq) ((rq)->flags & REQ_BLOCK_PC) #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) -- cgit v1.2.3 From 80d316b743aa85e2a3a0e449efc6feada77041a3 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Sun, 6 Apr 2003 19:22:40 -0700 Subject: [PATCH] generic HDLC update This version fixes: - missing rtnl_lock()/rtnl_unload() bug on unregister_hdlc_device - N2, C101: interrupt handler now works under high IRQ load from other devices (with previous versions, the IRQ processing for the card could sometimes stop after reaching "work limit") This is production-tested on devices I have access to (N2, C101, PC300, PCI200SYN). --- Documentation/networking/generic-hdlc.txt | 42 ++- drivers/net/wan/Kconfig | 41 ++ drivers/net/wan/Makefile | 1 + drivers/net/wan/c101.c | 76 ++-- drivers/net/wan/dscc4.c | 2 +- drivers/net/wan/farsync.c | 2 +- drivers/net/wan/hd6457x.c | 144 ++++--- drivers/net/wan/hdlc_cisco.c | 44 ++- drivers/net/wan/hdlc_fr.c | 603 ++++++++++++++++++++---------- drivers/net/wan/hdlc_generic.c | 37 +- drivers/net/wan/hdlc_ppp.c | 16 +- drivers/net/wan/hdlc_raw.c | 19 +- drivers/net/wan/hdlc_raw_eth.c | 110 ++++++ drivers/net/wan/hdlc_x25.c | 8 +- drivers/net/wan/n2.c | 159 +++----- include/linux/hdlc.h | 66 ++-- include/linux/hdlc/ioctl.h | 17 +- include/linux/if.h | 10 +- 18 files changed, 895 insertions(+), 502 deletions(-) create mode 100644 drivers/net/wan/hdlc_raw_eth.c (limited to 'include/linux') diff --git a/Documentation/networking/generic-hdlc.txt b/Documentation/networking/generic-hdlc.txt index 37631c95b90a..25dd993e0d3f 100644 --- a/Documentation/networking/generic-hdlc.txt +++ b/Documentation/networking/generic-hdlc.txt @@ -1,11 +1,13 @@ -Generic HDLC layer for Linux kernel 2.4/2.5 +Generic HDLC layer Krzysztof Halasa -May, 2001 +January, 2003 Generic HDLC layer currently supports: -- Frame Relay (ANSI, CCITT and no LMI), with ARP support (no InARP), -- raw HDLC (IPv4 only), +- Frame Relay (ANSI, CCITT and no LMI), with ARP support (no InARP). + Normal (routed) and Ethernet-bridged (Ethernet device emulation) + interfaces can share a single PVC. +- raw HDLC - either IP (IPv4) interface or Ethernet device emulation. - Cisco HDLC, - PPP (uses syncppp.c), - X.25 (uses X.25 routines). @@ -15,6 +17,10 @@ There are hardware drivers for the following cards: - RISCom/N2 by SDL Communications Inc. - and others, some not in the official kernel. +Ethernet device emulation (using HDLC or Frame-Relay PVC) is compatible +with IEEE 802.1Q (VLANs) and 802.1D (Ethernet bridging). + + Make sure the hdlc.o and the hardware driver are loaded. It should create a number of "hdlc" (hdlc0 etc) network devices, one for each WAN port. You'll need the "sethdlc" utility, get it from: @@ -58,6 +64,9 @@ Setting protocol: no-parity / crc16 / crc16-pr0 (CRC16 with preset zeros) / crc32-itu crc16-itu (CRC16 with ITU-T polynomial) / crc16-itu-pr0 - sets parity +* hdlc-eth - Ethernet device emulation using HDLC. Parity and encoding + as above. + * cisco - sets Cisco HDLC mode (IP, IPv6 and IPX supported) interval - time in seconds between keepalive packets timeout - time in seconds after last received keepalive packet before @@ -77,7 +86,12 @@ Setting protocol: n392 - error threshold - both user and network n393 - monitored events count - both user and network -* create | delete n - FR only - adds / deletes PVC interface with DLCI #n. +Frame-Relay only: +* create n | delete n - adds / deletes PVC interface with DLCI #n. + Newly created interface will be named pvc0, pvc1 etc. + +* create ether n | delete ether n - adds a device for Ethernet-bridged + frames. The device will be named pvceth0, pvceth1 etc. @@ -85,30 +99,30 @@ Setting protocol: Board-specific issues --------------------- -n2.o and c101.o need parameters to work (note double quotes): +n2.o and c101.o need parameters to work: - insmod n2 hw='"io,irq,ram,ports[:io,irq,...]"' + insmod n2 hw=io,irq,ram,ports[:io,irq,...] example: - insmod n2 hw='"0x300,10,0xD0000,01"' + insmod n2 hw=0x300,10,0xD0000,01 or - insmod c101 hw='"irq,ram[:irq,...]" + insmod c101 hw=irq,ram[:irq,...] example: - insmod c101 hw='"9,0xdc000"' + insmod c101 hw=9,0xdc000 If built into the kernel, these drivers need kernel (command line) parameters: - n2=io,irq,ram,ports:... + n2.hw=io,irq,ram,ports:... or - c101=irq,ram:... + c101.hw=irq,ram:... If you have a problem with N2 or C101 card, you can issue the "private" -command to see port's packet descriptor rings: +command to see port's packet descriptor rings (in kernel logs): sethdlc hdlc0 private -The hardware driver have to be build with CONFIG_HDLC_DEBUG_RINGS. +The hardware driver has to be build with CONFIG_HDLC_DEBUG_RINGS. Attaching this info to bug reports would be helpful. Anyway, let me know if you have problems using this. diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index dded2729c36c..8a6e03628073 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -253,6 +253,11 @@ config HDLC Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame Relay, synchronous Point-to-Point Protocol (PPP) and X.25. + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module + will be called hdlc.o. + If unsure, say N here. config HDLC_RAW @@ -264,6 +269,17 @@ config HDLC_RAW If unsure, say N here. +config HDLC_RAW_ETH + bool "Raw HDLC Ethernet device support" + depends on HDLC + help + Say Y to this option if you want generic HDLC driver to support + raw HDLC Ethernet device emulation over WAN (Wide Area Network) + connections. + You will need it for Ethernet over HDLC bridges. + + If unsure, say N here. + config HDLC_CISCO bool "Cisco HDLC support" depends on HDLC @@ -344,6 +360,11 @@ config N2 Note that N2csu and N2dds cards are not supported by this driver. + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called n2.o. + If unsure, say N here. config C101 @@ -354,6 +375,11 @@ config C101 Technologies Co., Ltd. If you have such a card, say Y here and see + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called c101.o. + If unsure, say N here. config FARSYNC @@ -377,18 +403,33 @@ config FARSYNC config HDLC_DEBUG_PKT bool "Debug received/transmitted packets" depends on HDLC + help + This option is for developers only - do NOT use on production + systems. config HDLC_DEBUG_HARD_HEADER bool "Debug hard_header routines" depends on HDLC + help + This option is for developers only - do NOT use on production + systems. config HDLC_DEBUG_ECN bool "Debug FECN/BECN conditions" depends on HDLC + help + This option is for developers only - do NOT use on production + systems. config HDLC_DEBUG_RINGS bool "Debug RX/TX packet rings" depends on HDLC + help + If you answer Y here you will be able to get a diagnostic dump of + port's TX and RX packet rings, using "sethdlc hdlcX private" + command. It does not affect normal operations. + + If unsure, say Y here. config DLCI tristate "Frame relay DLCI support" diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 5eef9b7d7c75..4d540014c93f 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -19,6 +19,7 @@ cyclomx-objs := $(cyclomx-y) hdlc-y := hdlc_generic.o hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o +hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index bf879f910abc..5995756d1016 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -1,12 +1,11 @@ /* * Moxa C101 synchronous serial card driver for Linux * - * Copyright (C) 2000-2002 Krzysztof Halasa + * Copyright (C) 2000-2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. * * For information see http://hq.pm.waw.pl/hdlc/ * @@ -23,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +31,7 @@ #include "hd64570.h" -static const char* version = "Moxa C101 driver version: 1.10"; +static const char* version = "Moxa C101 driver version: 1.14"; static const char* devname = "C101"; #define C101_PAGE 0x1D00 @@ -41,6 +41,10 @@ static const char* devname = "C101"; #define C101_MAPPED_RAM_SIZE 0x4000 #define RAM_SIZE (256 * 1024) +#define TX_RING_BUFFERS 10 +#define RX_RING_BUFFERS ((RAM_SIZE - C101_WINDOW_SIZE) / \ + (sizeof(pkt_desc) + HDLC_MAX_MRU) - TX_RING_BUFFERS) + #define CLOCK_BASE 9830400 /* 9.8304 MHz */ #define PAGE0_ALWAYS_MAPPED @@ -52,20 +56,20 @@ typedef struct card_s { spinlock_t lock; /* TX lock */ u8 *win0base; /* ISA window base address */ u32 phy_winbase; /* ISA physical base address */ - u16 buff_offset; /* offset of first buffer of first channel */ sync_serial_settings settings; + int rxpart; /* partial frame received, next frame invalid*/ unsigned short encoding; unsigned short parity; + u16 rx_ring_buffers; /* number of buffers in a ring */ + u16 tx_ring_buffers; + u16 buff_offset; /* offset of first buffer of first channel */ + u16 rxin; /* rx ring buffer 'in' pointer */ + u16 txin; /* tx ring buffer 'in' and 'last' pointers */ + u16 txlast; u8 rxs, txs, tmc; /* SCA registers */ u8 irq; /* IRQ (3-15) */ - u8 ring_buffers; /* number of buffers in a ring */ u8 page; - u8 rxin; /* rx ring buffer 'in' pointer */ - u8 txin; /* tx ring buffer 'in' and 'last' pointers */ - u8 txlast; - u8 rxpart; /* partial frame received, next frame invalid*/ - struct card_s *next_card; }card_t; @@ -78,7 +82,12 @@ static card_t **new_card = &first_card; #define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg)) #define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg)) #define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg)) -#define sca_outw(value, reg, card) writew(value, (card)->win0base + C101_SCA + (reg)) + +/* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */ +#define sca_outw(value, reg, card) do { \ + writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \ + writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg+1));\ +} while(0) #define port_to_card(port) (port) #define log_node(port) (0) @@ -146,11 +155,16 @@ static int c101_open(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); + + if (!try_module_get(THIS_MODULE)) + return -EFAULT; /* rmmod in progress */ + int result = hdlc_open(hdlc); - if (result) + if (result) { return result; + module_put(THIS_MODULE); + } - MOD_INC_USE_COUNT; writeb(1, port->win0base + C101_DTR); sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ sca_open(hdlc); @@ -168,7 +182,7 @@ static int c101_close(struct net_device *dev) writeb(0, port->win0base + C101_DTR); sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port); hdlc_close(hdlc); - MOD_DEC_USE_COUNT; + module_put(THIS_MODULE); return 0; } @@ -229,6 +243,8 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static void c101_destroy_card(card_t *card) { + readb(card->win0base + C101_PAGE); /* Resets SCA? */ + if (card->irq) free_irq(card->irq, card); @@ -242,7 +258,7 @@ static void c101_destroy_card(card_t *card) -static int c101_run(unsigned long irq, unsigned long winbase) +static int __init c101_run(unsigned long irq, unsigned long winbase) { struct net_device *dev; card_t *card; @@ -285,9 +301,10 @@ static int c101_run(unsigned long irq, unsigned long winbase) return -EBUSY; } - /* 2 rings required for 1 port */ - card->ring_buffers = (RAM_SIZE -C101_WINDOW_SIZE) / (2 * HDLC_MAX_MRU); - printk(KERN_DEBUG "c101: using %u packets rings\n",card->ring_buffers); + card->tx_ring_buffers = TX_RING_BUFFERS; + card->rx_ring_buffers = RX_RING_BUFFERS; + printk(KERN_DEBUG "c101: using %u TX + %u RX packets rings\n", + card->tx_ring_buffers, card->rx_ring_buffers); card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ @@ -337,7 +354,7 @@ static int __init c101_init(void) return -ENOSYS; /* no parameters specified, abort */ } - printk(KERN_INFO "%s (SCA-%s)\n", version, sca_version); + printk(KERN_INFO "%s\n", version); do { unsigned long irq, ram; @@ -352,7 +369,7 @@ static int __init c101_init(void) c101_run(irq, ram); if (*hw == '\x0') - return 0; + return first_card ? 0 : -ENOSYS; }while(*hw++ == ':'); printk(KERN_ERR "c101: invalid hardware parameters\n"); @@ -360,17 +377,6 @@ static int __init c101_init(void) } -#ifndef MODULE -static int __init c101_setup(char *str) -{ - hw = str; - return 1; -} - -__setup("c101=", c101_setup); -#endif - - static void __exit c101_cleanup(void) { card_t *card = first_card; @@ -389,5 +395,5 @@ module_exit(c101_cleanup); MODULE_AUTHOR("Krzysztof Halasa "); MODULE_DESCRIPTION("Moxa C101 serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_PARM(hw, "s"); /* hw=irq,ram:irq,... */ +MODULE_LICENSE("GPL v2"); +module_param(hw, charp, 0444); /* hw=irq,ram:irq,... */ diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index c5561f75cefb..21ab4da5b88c 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -620,7 +620,7 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, skb->tail += pkt_len; skb->len = pkt_len; if (netif_running(dev)) - skb->protocol = htons(ETH_P_HDLC); + skb->protocol = hdlc_type_trans(skb, dev); skb->dev->last_rx = jiffies; netif_rx(skb); } else { diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 01c96aea4eee..e583a6a4082e 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -761,7 +761,7 @@ fst_intr_rx ( struct fst_card_info *card, struct fst_port_info *port ) /* Push upstream */ skb->mac.raw = skb->data; skb->dev = hdlc_to_dev ( &port->hdlc ); - skb->protocol = htons ( ETH_P_HDLC ); + skb->protocol = hdlc_type_trans(skb, skb->dev); netif_rx ( skb ); port_to_dev ( port )->last_rx = jiffies; diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c index fb1d60d05a46..110ae6c03a3b 100644 --- a/drivers/net/wan/hd6457x.c +++ b/drivers/net/wan/hd6457x.c @@ -1,16 +1,29 @@ /* * Hitachi SCA HD64570 and HD64572 common driver for Linux * - * Copyright (C) 1998-2000 Krzysztof Halasa + * Copyright (C) 1998-2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. * * Sources of information: * Hitachi HD64570 SCA User's Manual * Hitachi HD64572 SCA-II User's Manual + * + * We use the following SCA memory map: + * + * Packet buffer descriptor rings - starting from winbase or win0base: + * rx_ring_buffers * sizeof(pkt_desc) = logical channel #0 RX ring + * tx_ring_buffers * sizeof(pkt_desc) = logical channel #0 TX ring + * rx_ring_buffers * sizeof(pkt_desc) = logical channel #1 RX ring (if used) + * tx_ring_buffers * sizeof(pkt_desc) = logical channel #1 TX ring (if used) + * + * Packet data buffers - starting from winbase + buff_offset: + * rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers + * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers + * rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers (if used) + * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used) */ #include @@ -42,8 +55,6 @@ #error Either hd64570.h or hd64572.h must be included #endif -static char sca_version[]="1.09"; - #define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) #define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET) #define get_dmac_tx(port) (phy_node(port) ? DMAC1TX_OFFSET : DMAC0TX_OFFSET) @@ -116,24 +127,35 @@ static inline port_t* dev_to_port(struct net_device *dev) -static inline u8 next_desc(port_t *port, u8 desc) +static inline u16 next_desc(port_t *port, u16 desc, int transmit) +{ + return (desc + 1) % (transmit ? port_to_card(port)->tx_ring_buffers + : port_to_card(port)->rx_ring_buffers); +} + + + +static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit) { - return (desc + 1) % port_to_card(port)->ring_buffers; + u16 rx_buffs = port_to_card(port)->rx_ring_buffers; + u16 tx_buffs = port_to_card(port)->tx_ring_buffers; + + desc %= (transmit ? tx_buffs : rx_buffs); // called with "X + 1" etc. + return log_node(port) * (rx_buffs + tx_buffs) + + transmit * rx_buffs + desc; } -static inline u16 desc_offset(port_t *port, u8 desc, u8 transmit) +static inline u16 desc_offset(port_t *port, u16 desc, int transmit) { /* Descriptor offset always fits in 16 bytes */ - u8 buffs = port_to_card(port)->ring_buffers; - return ((log_node(port) * 2 + transmit) * buffs + (desc % buffs)) * - sizeof(pkt_desc); + return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc); } -static inline pkt_desc* desc_address(port_t *port, u8 desc, u8 transmit) +static inline pkt_desc* desc_address(port_t *port, u16 desc, int transmit) { #ifdef PAGE0_ALWAYS_MAPPED return (pkt_desc*)(win0base(port_to_card(port)) @@ -146,12 +168,10 @@ static inline pkt_desc* desc_address(port_t *port, u8 desc, u8 transmit) -static inline u32 buffer_offset(port_t *port, u8 desc, u8 transmit) +static inline u32 buffer_offset(port_t *port, u16 desc, int transmit) { - u8 buffs = port_to_card(port)->ring_buffers; return port_to_card(port)->buff_offset + - ((log_node(port) * 2 + transmit) * buffs + (desc % buffs)) * - (u32)HDLC_MAX_MRU; + desc_abs_number(port, desc, transmit) * (u32)HDLC_MAX_MRU; } @@ -159,8 +179,7 @@ static inline u32 buffer_offset(port_t *port, u8 desc, u8 transmit) static void sca_init_sync_port(port_t *port) { card_t *card = port_to_card(port); - u8 transmit, i; - u16 dmac, buffs = card->ring_buffers; + int transmit, i; port->rxin = 0; port->txin = 0; @@ -171,6 +190,10 @@ static void sca_init_sync_port(port_t *port) #endif for (transmit = 0; transmit < 2; transmit++) { + u16 dmac = transmit ? get_dmac_tx(port) : get_dmac_rx(port); + u16 buffs = transmit ? card->tx_ring_buffers + : card->rx_ring_buffers; + for (i = 0; i < buffs; i++) { pkt_desc* desc = desc_address(port, i, transmit); u16 chain_off = desc_offset(port, i + 1, transmit); @@ -182,7 +205,6 @@ static void sca_init_sync_port(port_t *port) writeb(0, &desc->stat); } - dmac = transmit ? get_dmac_tx(port) : get_dmac_rx(port); /* DMA disable - to halt state */ sca_out(0, transmit ? DSR_TX(phy_node(port)) : DSR_RX(phy_node(port)), card); @@ -247,7 +269,7 @@ static inline void sca_msci_intr(port_t *port) -static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u8 rxin) +static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u16 rxin) { struct sk_buff *skb; u16 len; @@ -294,7 +316,7 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u8 rxin) skb->mac.raw = skb->data; skb->dev = hdlc_to_dev(&port->hdlc); skb->dev->last_rx = jiffies; - skb->protocol = htons(ETH_P_HDLC); + skb->protocol = hdlc_type_trans(skb, hdlc_to_dev(&port->hdlc)); netif_rx(skb); } @@ -341,7 +363,7 @@ static inline void sca_rx_intr(port_t *port) /* Set new error descriptor address */ sca_outa(desc_off, dmac + EDAL, card); - port->rxin = next_desc(port, port->rxin); + port->rxin = next_desc(port, port->rxin, 0); } /* make sure RX DMA is enabled */ @@ -377,8 +399,7 @@ static inline void sca_tx_intr(port_t *port) port->hdlc.stats.tx_packets++; port->hdlc.stats.tx_bytes += readw(&desc->len); writeb(0, &desc->stat); /* Free descriptor */ - port->txlast = (port->txlast + 1) % - port_to_card(port)->ring_buffers; + port->txlast = next_desc(port, port->txlast, 1); } netif_wake_queue(hdlc_to_dev(&port->hdlc)); @@ -390,8 +411,6 @@ static inline void sca_tx_intr(port_t *port) static void sca_intr(int irq, void* dev_id, struct pt_regs *regs) { card_t *card = dev_id; -/* Maximum events to handle at each interrupt - should I increase it? */ - int boguscnt = 4; int i; u8 stat; @@ -412,19 +431,9 @@ static void sca_intr(int irq, void* dev_id, struct pt_regs *regs) if (stat & SCA_INTR_DMAC_TX(i)) sca_tx_intr(port); } - - if (--boguscnt < 0) { -#if 0 - printk(KERN_ERR "%s: too much work at " - "interrupt\n", - hdlc_to_name(&port->hdlc)); -#endif - goto exit; - } } } - exit: #ifndef ALL_PAGES_ALWAYS_MAPPED openwin(card, page); /* Restore original page */ #endif @@ -435,7 +444,7 @@ static void sca_intr(int irq, void* dev_id, struct pt_regs *regs) static void sca_set_port(port_t *port) { card_t* card = port_to_card(port); - u8 msci = get_msci(port); + u16 msci = get_msci(port); u8 md2 = sca_in(msci + MD2, card); unsigned int tmc, br = 10, brv = 1024; @@ -495,7 +504,7 @@ static void sca_open(hdlc_device *hdlc) { port_t *port = hdlc_to_port(hdlc); card_t* card = port_to_card(port); - u8 msci = get_msci(port); + u16 msci = get_msci(port); u8 md0, md2; switch(port->encoding) { @@ -516,7 +525,7 @@ static void sca_open(hdlc_device *hdlc) case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break; #else case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break; -#endif +#endif case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break; default: md0 = MD0_HDLC | MD0_CRC_NONE; } @@ -613,7 +622,7 @@ static int sca_attach(hdlc_device *hdlc, unsigned short encoding, parity != PARITY_CRC16_PR0_CCITT && #else parity != PARITY_CRC32_PR1_CCITT && -#endif +#endif parity != PARITY_CRC16_PR1_CCITT) return -EINVAL; @@ -639,14 +648,13 @@ static void sca_dump_rings(hdlc_device *hdlc) openwin(card, 0); #endif - printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u " - "%sactive", + printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", sca_ina(get_dmac_rx(port) + CDAL, card), sca_ina(get_dmac_rx(port) + EDAL, card), sca_in(DSR_RX(phy_node(port)), card), port->rxin, sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); - for (cnt = 0; cntring_buffers; cnt++) + for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++) printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); @@ -658,7 +666,7 @@ static void sca_dump_rings(hdlc_device *hdlc) port->txlast, sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); - for (cnt = 0; cntring_buffers; cnt++) + for (cnt = 0; cnt < port_to_card(port)->tx_ring_buffers; cnt++) printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); printk("\n"); @@ -750,7 +758,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) writeb(ST_TX_EOM, &desc->stat); dev->trans_start = jiffies; - port->txin = next_desc(port, port->txin); + port->txin = next_desc(port, port->txin, 1); sca_outa(desc_offset(port, port->txin, 1), get_dmac_tx(port) + EDAL, card); @@ -767,7 +775,49 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) } -static void sca_init(card_t *card, int wait_states) + +#ifdef NEED_DETECT_RAM +static u32 __devinit sca_detect_ram(card_t *card, u8 *rambase, u32 ramsize) +{ + /* Round RAM size to 32 bits, fill from end to start */ + u32 i = ramsize &= ~3; + +#ifndef ALL_PAGES_ALWAYS_MAPPED + u32 size = winsize(card); + + openwin(card, (i - 4) / size); /* select last window */ +#endif + do { + i -= 4; +#ifndef ALL_PAGES_ALWAYS_MAPPED + if ((i + 4) % size == 0) + openwin(card, i / size); + writel(i ^ 0x12345678, rambase + i % size); +#else + writel(i ^ 0x12345678, rambase + i); +#endif + }while (i > 0); + + for (i = 0; i < ramsize ; i += 4) { +#ifndef ALL_PAGES_ALWAYS_MAPPED + if (i % size == 0) + openwin(card, i / size); + + if (readl(rambase + i % size) != (i ^ 0x12345678)) + break; +#else + if (readl(rambase + i) != (i ^ 0x12345678)) + break; +#endif + } + + return i; +} +#endif /* NEED_DETECT_RAM */ + + + +static void __devinit sca_init(card_t *card, int wait_states) { sca_out(wait_states, WCRL, card); /* Wait Control */ sca_out(wait_states, WCRM, card); diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 4d837aea20b1..f6234c5a64cc 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -2,12 +2,11 @@ * Generic HDLC support routines for Linux * Cisco HDLC support * - * Copyright (C) 2000 - 2001 Krzysztof Halasa + * Copyright (C) 2000 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. */ #include @@ -80,17 +79,43 @@ static void cisco_keepalive_send(hdlc_device *hdlc, u32 type, data->par1 = htonl(par1); data->par2 = htonl(par2); data->rel = 0xFFFF; - data->time = htonl(jiffies * 1000 / HZ); + /* we will need do_div here if 1000 % HZ != 0 */ + data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ)); skb_put(skb, sizeof(cisco_packet)); skb->priority = TC_PRIO_CONTROL; skb->dev = hdlc_to_dev(hdlc); + skb->nh.raw = skb->data; dev_queue_xmit(skb); } +static unsigned short cisco_type_trans(struct sk_buff *skb, + struct net_device *dev) +{ + hdlc_header *data = (hdlc_header*)skb->data; + + if (skb->len < sizeof(hdlc_header)) + return __constant_htons(ETH_P_HDLC); + + if (data->address != CISCO_MULTICAST && + data->address != CISCO_UNICAST) + return __constant_htons(ETH_P_HDLC); + + switch(data->protocol) { + case __constant_htons(ETH_P_IP): + case __constant_htons(ETH_P_IPX): + case __constant_htons(ETH_P_IPV6): + skb_pull(skb, sizeof(hdlc_header)); + return data->protocol; + default: + return __constant_htons(ETH_P_HDLC); + } +} + + static void cisco_rx(struct sk_buff *skb) { hdlc_device *hdlc = dev_to_hdlc(skb->dev); @@ -109,14 +134,6 @@ static void cisco_rx(struct sk_buff *skb) skb_pull(skb, sizeof(hdlc_header)); switch(ntohs(data->protocol)) { - case ETH_P_IP: - case ETH_P_IPX: - case ETH_P_IPV6: - skb->protocol = data->protocol; - skb->dev = hdlc_to_dev(hdlc); - netif_rx(skb); - return; - case CISCO_SYS_INFO: /* Packet is not needed, drop it. */ dev_kfree_skb_any(skb); @@ -288,6 +305,7 @@ int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc->open = cisco_open; hdlc->stop = cisco_close; hdlc->netif_rx = cisco_rx; + hdlc->type_trans = cisco_type_trans; hdlc->proto = IF_PROTO_CISCO; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = cisco_hard_header; diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 20a67ed26811..c0b5f1821043 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -2,13 +2,22 @@ * Generic HDLC support routines for Linux * Frame Relay support * - * Copyright (C) 1999 - 2001 Krzysztof Halasa + * Copyright (C) 1999 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + + Theory of PVC state in DCE mode: + + (exist,new) -> 0,0 when "PVC create" or if "link unreliable" + 0,x -> 1,1 if "link reliable" when sending FULL STATUS + 1,1 -> 1,0 if received FULL STATUS ACK + + (active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create" + -> 1 when "PVC up" and (exist,new) = 1,0 +*/ #include #include @@ -20,19 +29,23 @@ #include #include #include +#include #include #include #include +#include #include __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { - pvc_device *pvc=hdlc->state.fr.first_pvc; - - while (pvc) { - if (netdev_dlci(&pvc->netdev) == dlci) + pvc_device *pvc = hdlc->state.fr.first_pvc; + + while(pvc) { + if (pvc->dlci == dlci) return pvc; + if (pvc->dlci > dlci) + return NULL; /* the listed is sorted */ pvc = pvc->next; } @@ -40,18 +53,72 @@ __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) } +__inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) +{ + pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; + + while(*pvc_p) { + if ((*pvc_p)->dlci == dlci) + return *pvc_p; + if ((*pvc_p)->dlci > dlci) + break; /* the listed is sorted */ + pvc_p = &(*pvc_p)->next; + } + + pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC); + if (!pvc) + return NULL; + + memset(pvc, 0, sizeof(pvc_device)); + pvc->dlci = dlci; + pvc->master = hdlc; + pvc->next = *pvc_p; /* Put it in the chain */ + *pvc_p = pvc; + return pvc; +} + + +__inline__ int pvc_is_used(pvc_device *pvc) +{ + return pvc->main != NULL || pvc->ether != NULL; +} + + +__inline__ void delete_unused_pvcs(hdlc_device *hdlc) +{ + pvc_device **pvc_p = &hdlc->state.fr.first_pvc; + + while(*pvc_p) { + if (!pvc_is_used(*pvc_p)) { + pvc_device *pvc = *pvc_p; + *pvc_p = pvc->next; + kfree(pvc); + continue; + } + pvc_p = &(*pvc_p)->next; + } +} + + +__inline__ struct net_device** get_dev_p(pvc_device *pvc, int type) +{ + if (type == ARPHRD_ETHER) + return &pvc->ether; + else + return &pvc->main; +} + -__inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, - int *active, int *new) +__inline__ u16 status_to_dlci(u8 *status, int *active, int *new) { - *new = (status[2] & 0x08); - *active = (!*new && (status[2] & 0x02)); + *new = (status[2] & 0x08) ? 1 : 0; + *active = (status[2] & 0x02) ? 1 : 0; return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3); } -__inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status, +__inline__ void dlci_to_status(u16 dlci, u8 *status, int active, int new) { status[0] = (dlci>>4) & 0x3F; @@ -66,37 +133,50 @@ __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status, -static int fr_hard_header(struct sk_buff *skb, struct net_device *dev, - u16 type, void *daddr, void *saddr, unsigned int len) +static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) { u16 head_len; + struct sk_buff *skb = *skb_p; - if (!daddr) - daddr = dev->broadcast; - -#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER - printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name); -#endif - - switch(type) { - case ETH_P_IP: + switch(skb->protocol) { + case __constant_ntohs(ETH_P_IP): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_IP; break; - case ETH_P_IPV6: + case __constant_ntohs(ETH_P_IPV6): head_len = 4; skb_push(skb, head_len); skb->data[3] = NLPID_IPV6; break; - case LMI_PROTO: + case __constant_ntohs(LMI_PROTO): head_len = 4; skb_push(skb, head_len); skb->data[3] = LMI_PROTO; break; + case __constant_ntohs(ETH_P_802_3): + head_len = 10; + if (skb_headroom(skb) < head_len) { + struct sk_buff *skb2 = skb_realloc_headroom(skb, + head_len); + if (!skb2) + return -ENOBUFS; + dev_kfree_skb(skb); + skb = *skb_p = skb2; + } + skb_push(skb, head_len); + skb->data[3] = FR_PAD; + skb->data[4] = NLPID_SNAP; + skb->data[5] = FR_PAD; + skb->data[6] = 0x80; + skb->data[7] = 0xC2; + skb->data[8] = 0x00; + skb->data[9] = 0x07; /* bridged Ethernet frame w/out FCS */ + break; + default: head_len = 10; skb_push(skb, head_len); @@ -105,14 +185,12 @@ static int fr_hard_header(struct sk_buff *skb, struct net_device *dev, skb->data[5] = FR_PAD; skb->data[6] = FR_PAD; skb->data[7] = FR_PAD; - skb->data[8] = type>>8; - skb->data[9] = (u8)type; + *(u16*)(skb->data + 8) = skb->protocol; } - memcpy(skb->data, daddr, 2); + dlci_to_q922(skb->data, dlci); skb->data[2] = FR_UI; - - return head_len; + return 0; } @@ -124,13 +202,12 @@ static int pvc_open(struct net_device *dev) if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0) return -EIO; /* Master must be UP in order to activate PVC */ - if (pvc->master->state.fr.settings.lmi != LMI_NONE) - pvc->state.active = 0; - else - pvc->state.active = 1; + if (pvc->open_count++ == 0) { + if (pvc->master->state.fr.settings.lmi == LMI_NONE) + pvc->state.active = 1; - pvc->state.new = 0; - pvc->master->state.fr.changed = 1; + pvc->master->state.fr.dce_changed = 1; + } return 0; } @@ -139,38 +216,94 @@ static int pvc_open(struct net_device *dev) static int pvc_close(struct net_device *dev) { pvc_device *pvc = dev_to_pvc(dev); - pvc->state.active = pvc->state.new = 0; - pvc->master->state.fr.changed = 1; + + if (--pvc->open_count == 0) { + if (pvc->master->state.fr.settings.lmi == LMI_NONE) + pvc->state.active = 0; + + if (pvc->master->state.fr.settings.dce) { + pvc->master->state.fr.dce_changed = 1; + pvc->state.active = 0; + } + } return 0; } -static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) +int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { pvc_device *pvc = dev_to_pvc(dev); + fr_proto_pvc_info info; - if (pvc->state.active) { - skb->dev = hdlc_to_dev(pvc->master); - pvc->stats.tx_bytes += skb->len; - pvc->stats.tx_packets++; - if (pvc->state.fecn) - pvc->stats.tx_compressed++; /* TX Congestion counter */ - dev_queue_xmit(skb); - } else { - pvc->stats.tx_dropped++; - dev_kfree_skb(skb); + if (ifr->ifr_settings.type == IF_GET_PROTO) { + if (dev->type == ARPHRD_ETHER) + ifr->ifr_settings.type = IF_PROTO_FR_ETH_PVC; + else + ifr->ifr_settings.type = IF_PROTO_FR_PVC; + + if (ifr->ifr_settings.size < sizeof(info)) { + /* data size wanted */ + ifr->ifr_settings.size = sizeof(info); + return -ENOBUFS; + } + + info.dlci = pvc->dlci; + memcpy(info.master, hdlc_to_name(pvc->master), IFNAMSIZ); + if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info, + &info, sizeof(info))) + return -EFAULT; + return 0; } - return 0; + return -EINVAL; +} + + +__inline__ struct net_device_stats *pvc_get_stats(struct net_device *dev) +{ + return (struct net_device_stats *) + ((char *)dev + sizeof(struct net_device)); } -static struct net_device_stats *pvc_get_stats(struct net_device *dev) +static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) { pvc_device *pvc = dev_to_pvc(dev); - return &pvc->stats; + struct net_device_stats *stats = pvc_get_stats(dev); + + if (pvc->state.active) { + if (dev->type == ARPHRD_ETHER) { + int pad = ETH_ZLEN - skb->len; + if (pad > 0) { /* Pad the frame with zeros */ + int len = skb->len; + if (skb_tailroom(skb) < pad) + if (pskb_expand_head(skb, 0, pad, + GFP_ATOMIC)) { + stats->tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + skb_put(skb, pad); + memset(skb->data + len, 0, pad); + } + skb->protocol = __constant_htons(ETH_P_802_3); + } + if (!fr_hard_header(&skb, pvc->dlci)) { + stats->tx_bytes += skb->len; + stats->tx_packets++; + if (pvc->state.fecn) /* TX Congestion counter */ + stats->tx_compressed++; + skb->dev = hdlc_to_dev(pvc->master); + dev_queue_xmit(skb); + return 0; + } + } + + stats->tx_dropped++; + dev_kfree_skb(skb); + return 0; } @@ -187,9 +320,15 @@ static int pvc_change_mtu(struct net_device *dev, int new_mtu) static inline void fr_log_dlci_active(pvc_device *pvc) { - printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc), - pvc->state.active ? "" : "in", - pvc->state.new ? " new" : ""); + printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n", + hdlc_to_name(pvc->master), + pvc->dlci, + pvc->main ? pvc->main->name : "", + pvc->main && pvc->ether ? " " : "", + pvc->ether ? pvc->ether->name : "", + pvc->state.new ? " new" : "", + !pvc->state.exist ? "deleted" : + pvc->state.active ? "active" : "inactive"); } @@ -213,8 +352,8 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) int i = 0; if (hdlc->state.fr.settings.dce && fullrep) { - len += hdlc->state.fr.pvc_count * (2 + stat_len); - if (len > HDLC_MAX_MTU) { + len += hdlc->state.fr.dce_pvc_count * (2 + stat_len); + if (len > HDLC_MAX_MRU) { printk(KERN_WARNING "%s: Too many PVCs while sending " "LMI full report\n", hdlc_to_name(hdlc)); return; @@ -224,12 +363,13 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) skb = dev_alloc_skb(len); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n", - hdlc_to_name(hdlc)); + hdlc_to_name(hdlc)); return; } memset(skb->data, 0, len); skb_reserve(skb, 4); - fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0); + skb->protocol = __constant_htons(LMI_PROTO); + fr_hard_header(&skb, LMI_DLCI); data = skb->tail; data[i++] = LMI_CALLREF; data[i++] = hdlc->state.fr.settings.dce @@ -253,16 +393,20 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT; data[i++] = stat_len; - if (hdlc->state.fr.reliable && - (pvc->netdev.flags & IFF_UP) && - !pvc->state.active && - !pvc->state.new) { - pvc->state.new = 1; + /* LMI start/restart */ + if (hdlc->state.fr.reliable && !pvc->state.exist) { + pvc->state.exist = pvc->state.new = 1; + fr_log_dlci_active(pvc); + } + + /* ifconfig PVC up */ + if (pvc->open_count && !pvc->state.active && + pvc->state.exist && !pvc->state.new) { + pvc->state.active = 1; fr_log_dlci_active(pvc); } - dlci_to_status(hdlc, netdev_dlci(&pvc->netdev), - data + i, + dlci_to_status(pvc->dlci, data + i, pvc->state.active, pvc->state.new); i += stat_len; pvc = pvc->next; @@ -272,6 +416,7 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) skb_put(skb, i); skb->priority = TC_PRIO_CONTROL; skb->dev = hdlc_to_dev(hdlc); + skb->nh.raw = skb->data; dev_queue_xmit(skb); } @@ -312,10 +457,11 @@ static void fr_timer(unsigned long arg) if (reliable) { hdlc->state.fr.n391cnt = 0; /* Request full status */ - hdlc->state.fr.changed = 1; + hdlc->state.fr.dce_changed = 1; } else { while (pvc) { /* Deactivate all PVCs */ - pvc->state.new = pvc->state.active = 0; + pvc->state.exist = 0; + pvc->state.active = pvc->state.new = 0; pvc = pvc->next; } } @@ -346,7 +492,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) { int stat_len; pvc_device *pvc; - int reptype = -1, error; + int reptype = -1, error, no_ram; u8 rxseq, txseq; int i; @@ -420,20 +566,18 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) while (pvc) { if (pvc->state.new) { pvc->state.new = 0; - pvc->state.active = 1; - fr_log_dlci_active(pvc); /* Tell DTE that new PVC is now active */ - hdlc->state.fr.changed = 1; + hdlc->state.fr.dce_changed = 1; } pvc = pvc->next; } } - if (hdlc->state.fr.changed) { + if (hdlc->state.fr.dce_changed) { reptype = LMI_FULLREP; hdlc->state.fr.fullrep_sent = 1; - hdlc->state.fr.changed = 0; + hdlc->state.fr.dce_changed = 0; } fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0); @@ -449,13 +593,14 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) pvc = hdlc->state.fr.first_pvc; while (pvc) { - pvc->state.deleted = pvc->state.active; /* mark active PVCs */ + pvc->state.deleted = 1; pvc = pvc->next; } + no_ram = 0; while (skb->len >= i + 2 + stat_len) { u16 dlci; - int active, new; + unsigned int active, new; if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT) ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) { @@ -472,21 +617,28 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) } i++; - dlci = status_to_dlci(hdlc, skb->data + i, &active, &new); - pvc = find_pvc(hdlc, dlci); + dlci = status_to_dlci(skb->data + i, &active, &new); + + pvc = add_pvc(hdlc, dlci); + + if (!pvc && !no_ram) { + printk(KERN_WARNING + "%s: Memory squeeze on fr_lmi_recv()\n", + hdlc_to_name(hdlc)); + no_ram = 1; + } - active |= new; if (pvc) { - if (active && !pvc->state.active && - (pvc->netdev.flags & IFF_UP)) { + pvc->state.exist = 1; + pvc->state.deleted = 0; + if (active != pvc->state.active || + new != pvc->state.new || + !pvc->state.exist) { + pvc->state.new = new; pvc->state.active = active; fr_log_dlci_active(pvc); } - pvc->state.deleted = 0; } - else if (new) - printk(KERN_INFO "%s: new PVC available, DLCI=%u\n", - hdlc_to_name(hdlc), dlci); i += stat_len; } @@ -494,10 +646,10 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) pvc = hdlc->state.fr.first_pvc; while (pvc) { - if (pvc->state.deleted) { + if (pvc->state.deleted && pvc->state.exist) { pvc->state.active = pvc->state.new = 0; + pvc->state.exist = 0; fr_log_dlci_active(pvc); - pvc->state.deleted = 0; } pvc = pvc->next; } @@ -517,8 +669,9 @@ static void fr_rx(struct sk_buff *skb) u8 *data = skb->data; u16 dlci; pvc_device *pvc; + struct net_device *dev = NULL; - if (skb->len<4 || fh->ea1 || data[2] != FR_UI) + if (skb->len <= 4 || fh->ea1 || data[2] != FR_UI) goto rx_error; dlci = q922_to_dlci(skb->data); @@ -550,57 +703,39 @@ static void fr_rx(struct sk_buff *skb) printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", hdlc_to_name(hdlc), dlci); #endif - goto rx_error; - } - - if ((pvc->netdev.flags & IFF_UP) == 0) { -#ifdef CONFIG_HDLC_DEBUG_PKT - printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n", - hdlc_to_name(hdlc), dlci); -#endif - goto rx_error; + dev_kfree_skb_any(skb); + return; } - pvc->stats.rx_packets++; /* PVC traffic */ - pvc->stats.rx_bytes += skb->len; - - if (pvc->state.fecn != (fh->fecn ? PVC_STATE_FECN : 0)) { + if (pvc->state.fecn != fh->fecn) { #ifdef CONFIG_HDLC_DEBUG_ECN - printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc), - fh->fecn ? "N" : "FF"); + printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc), + dlci, fh->fecn ? "N" : "FF"); #endif pvc->state.fecn ^= 1; } - if (pvc->state.becn != (fh->becn ? PVC_STATE_BECN : 0)) { + if (pvc->state.becn != fh->becn) { #ifdef CONFIG_HDLC_DEBUG_ECN - printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc), - fh->becn ? "N" : "FF"); + printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc), + dlci, fh->becn ? "N" : "FF"); #endif pvc->state.becn ^= 1; } - if (pvc->state.becn) - pvc->stats.rx_compressed++; - - skb->dev = &pvc->netdev; if (data[3] == NLPID_IP) { skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + dev = pvc->main; skb->protocol = htons(ETH_P_IP); - netif_rx(skb); - return; - } - - if (data[3] == NLPID_IPV6) { + } else if (data[3] == NLPID_IPV6) { skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + dev = pvc->main; skb->protocol = htons(ETH_P_IPV6); - netif_rx(skb); - return; - } - if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) { + } else if (skb->len > 10 && data[3] == FR_PAD && + data[4] == NLPID_SNAP && data[5] == FR_PAD) { u16 oui = ntohs(*(u16*)(data + 6)); u16 pid = ntohs(*(u16*)(data + 8)); skb_pull(skb, 10); @@ -610,23 +745,39 @@ static void fr_rx(struct sk_buff *skb) case ETH_P_IPX: case ETH_P_IP: /* a long variant */ case ETH_P_IPV6: + dev = pvc->main; skb->protocol = htons(pid); break; + case 0x80C20007: /* bridged Ethernet frame */ + if ((dev = pvc->ether) != NULL) + skb->protocol = eth_type_trans(skb, dev); + break; + default: printk(KERN_INFO "%s: Unsupported protocol, OUI=%x " "PID=%x\n", hdlc_to_name(hdlc), oui, pid); dev_kfree_skb_any(skb); return; } - - netif_rx(skb); + } else { + printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x " + "length = %i\n", hdlc_to_name(hdlc), data[3], skb->len); + dev_kfree_skb_any(skb); return; } - printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x\n", - hdlc_to_name(hdlc), data[3]); - dev_kfree_skb_any(skb); + if (dev) { + struct net_device_stats *stats = pvc_get_stats(dev); + stats->rx_packets++; /* PVC traffic */ + stats->rx_bytes += skb->len; + if (pvc->state.becn) + stats->rx_compressed++; + skb->dev = dev; + netif_rx(skb); + } else + dev_kfree_skb_any(skb); + return; rx_error: @@ -641,7 +792,7 @@ static int fr_open(hdlc_device *hdlc) if (hdlc->state.fr.settings.lmi != LMI_NONE) { hdlc->state.fr.last_poll = 0; hdlc->state.fr.reliable = 0; - hdlc->state.fr.changed = 1; + hdlc->state.fr.dce_changed = 1; hdlc->state.fr.request = 0; hdlc->state.fr.fullrep_sent = 0; hdlc->state.fr.last_errors = 0xFFFFFFFF; @@ -669,90 +820,119 @@ static void fr_close(hdlc_device *hdlc) if (hdlc->state.fr.settings.lmi != LMI_NONE) del_timer_sync(&hdlc->state.fr.timer); - while(pvc) { - dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */ + while(pvc) { /* Shutdown all PVCs for this FRAD */ + if (pvc->main) + dev_close(pvc->main); + if (pvc->ether) + dev_close(pvc->ether); + pvc->state.active = pvc->state.new = pvc->state.fecn = + pvc->state.becn = 0; + pvc->state.exist = 0; pvc = pvc->next; } } - -static int fr_pvc(hdlc_device *hdlc, unsigned int dlci, int create) +static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) { - pvc_device **pvc_p = &hdlc->state.fr.first_pvc; - pvc_device *pvc; - int result; + pvc_device *pvc = NULL; + struct net_device *dev; + int result, used; + char * prefix = "pvc%d"; - if(dlci <= 0 || dlci >= 1024) - return -EINVAL; /* Only 10 bits for DLCI, DLCI 0 reserved */ + if (type == ARPHRD_ETHER) + prefix = "pvceth%d"; - while(*pvc_p) { - if (netdev_dlci(&(*pvc_p)->netdev) == dlci) - break; - pvc_p = &(*pvc_p)->next; + if ((pvc = add_pvc(hdlc, dlci)) == NULL) { + printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", + hdlc_to_name(hdlc)); + return -ENOBUFS; } - if (create) { /* Create PVC */ - if (*pvc_p != NULL) - return -EEXIST; + if (*get_dev_p(pvc, type)) + return -EEXIST; - pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL); - if (!pvc) { - printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n", - hdlc_to_name(hdlc)); - return -ENOBUFS; - } - memset(pvc, 0, sizeof(pvc_device)); - - pvc->netdev.hard_start_xmit = pvc_xmit; - pvc->netdev.get_stats = pvc_get_stats; - pvc->netdev.open = pvc_open; - pvc->netdev.stop = pvc_close; - pvc->netdev.change_mtu = pvc_change_mtu; - pvc->netdev.mtu = HDLC_MAX_MTU; - - pvc->netdev.type = ARPHRD_DLCI; - pvc->netdev.hard_header_len = 16; - pvc->netdev.hard_header = fr_hard_header; - pvc->netdev.tx_queue_len = 0; - pvc->netdev.flags = IFF_POINTOPOINT; - - pvc->master = hdlc; - *(u16*)pvc->netdev.dev_addr = htons(dlci); - dlci_to_q922(pvc->netdev.broadcast, dlci); - pvc->netdev.addr_len = 2; - - result = dev_alloc_name(&pvc->netdev, "pvc%d"); - if (result < 0) { - kfree(pvc); - *pvc_p = NULL; - return result; - } + used = pvc_is_used(pvc); - if (register_netdevice(&pvc->netdev) != 0) { - kfree(pvc); - *pvc_p = NULL; - return -EIO; - } + dev = kmalloc(sizeof(struct net_device) + + sizeof(struct net_device_stats), GFP_KERNEL); + if (!dev) { + printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n", + hdlc_to_name(hdlc)); + delete_unused_pvcs(hdlc); + return -ENOBUFS; + } + memset(dev, 0, sizeof(struct net_device) + + sizeof(struct net_device_stats)); - hdlc->state.fr.changed = 1; - hdlc->state.fr.pvc_count++; - return 0; + if (type == ARPHRD_ETHER) { + ether_setup(dev); + memcpy(dev->dev_addr, "\x00\x01", 2); + get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); + } else { + dev->type = ARPHRD_DLCI; + dev->flags = IFF_POINTOPOINT; + dev->hard_header_len = 10; + dev->addr_len = 2; + *(u16*)dev->dev_addr = htons(dlci); + dlci_to_q922(dev->broadcast, dlci); } + dev->hard_start_xmit = pvc_xmit; + dev->get_stats = pvc_get_stats; + dev->open = pvc_open; + dev->stop = pvc_close; + dev->do_ioctl = pvc_ioctl; + dev->change_mtu = pvc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + dev->tx_queue_len = 0; + dev->priv = pvc; + + result = dev_alloc_name(dev, prefix); + if (result < 0) { + kfree(dev); + delete_unused_pvcs(hdlc); + return result; + } + + if (register_netdevice(dev) != 0) { + kfree(dev); + delete_unused_pvcs(hdlc); + return -EIO; + } + + *get_dev_p(pvc, type) = dev; + if (!used) { + hdlc->state.fr.dce_changed = 1; + hdlc->state.fr.dce_pvc_count++; + } + return 0; +} + + + +static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) +{ + pvc_device *pvc; + struct net_device *dev; - if (*pvc_p == NULL) /* Delete PVC */ + if ((pvc = find_pvc(hdlc, dlci)) == NULL) return -ENOENT; - pvc = *pvc_p; + if ((dev = *get_dev_p(pvc, type)) == NULL) + return -ENOENT; - if (pvc->netdev.flags & IFF_UP) + if (dev->flags & IFF_UP) return -EBUSY; /* PVC in use */ - hdlc->state.fr.changed = 1; - hdlc->state.fr.pvc_count--; - *pvc_p = pvc->next; - unregister_netdevice(&pvc->netdev); - kfree(pvc); + unregister_netdevice(dev); + kfree(dev); + *get_dev_p(pvc, type) = NULL; + + if (!pvc_is_used(pvc)) { + hdlc->state.fr.dce_pvc_count--; + hdlc->state.fr.dce_changed = 1; + } + delete_unused_pvcs(hdlc); return 0; } @@ -763,14 +943,21 @@ static void fr_destroy(hdlc_device *hdlc) pvc_device *pvc = hdlc->state.fr.first_pvc; while(pvc) { pvc_device *next = pvc->next; - unregister_netdev(&pvc->netdev); + if (pvc->main) { + unregister_netdevice(pvc->main); + kfree(pvc->main); + } + if (pvc->ether) { + unregister_netdevice(pvc->ether); + kfree(pvc->ether); + } kfree(pvc); pvc = next; } hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ - hdlc->state.fr.pvc_count = 0; - hdlc->state.fr.changed = 1; + hdlc->state.fr.dce_pvc_count = 0; + hdlc->state.fr.dce_changed = 1; } @@ -828,25 +1015,27 @@ int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr) if (hdlc->proto != IF_PROTO_FR) { hdlc_proto_detach(hdlc); hdlc->state.fr.first_pvc = NULL; - hdlc->state.fr.pvc_count = 0; + hdlc->state.fr.dce_pvc_count = 0; } memcpy(&hdlc->state.fr.settings, &new_settings, size); hdlc->open = fr_open; hdlc->stop = fr_close; hdlc->netif_rx = fr_rx; + hdlc->type_trans = NULL; hdlc->proto_detach = fr_destroy; hdlc->proto = IF_PROTO_FR; dev->hard_start_xmit = hdlc->xmit; - dev->hard_header = fr_hard_header; + dev->hard_header = NULL; dev->type = ARPHRD_FRAD; - dev->addr_len = 2; - *(u16*)dev->dev_addr = htons(LMI_DLCI); - dlci_to_q922(dev->broadcast, LMI_DLCI); + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + dev->addr_len = 0; return 0; case IF_PROTO_FR_ADD_PVC: case IF_PROTO_FR_DEL_PVC: + case IF_PROTO_FR_ADD_ETH_PVC: + case IF_PROTO_FR_DEL_ETH_PVC: if(!capable(CAP_NET_ADMIN)) return -EPERM; @@ -854,8 +1043,20 @@ int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr) sizeof(fr_proto_pvc))) return -EFAULT; - return fr_pvc(hdlc, pvc.dlci, - ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC); + if (pvc.dlci <= 0 || pvc.dlci >= 1024) + return -EINVAL; /* Only 10 bits, DLCI 0 reserved */ + + if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC || + ifr->ifr_settings.type == IF_PROTO_FR_DEL_ETH_PVC) + result = ARPHRD_ETHER; /* bridged Ethernet device */ + else + result = ARPHRD_DLCI; + + if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC || + ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC) + return fr_add_pvc(hdlc, pvc.dlci, result); + else + return fr_del_pvc(hdlc, pvc.dlci, result); } return -EINVAL; diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c index 09d2b24b109c..f003d03844d3 100644 --- a/drivers/net/wan/hdlc_generic.c +++ b/drivers/net/wan/hdlc_generic.c @@ -1,17 +1,13 @@ /* * Generic HDLC support routines for Linux * - * Copyright (C) 1999 - 2001 Krzysztof Halasa + * Copyright (C) 1999 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. * - * Current status: - * - this is work in progress - * - not heavily tested on SMP - * - currently supported: + * Currently supported: * * raw IP-in-HDLC * * Cisco HDLC * * Frame Relay with ANSI or CCITT LMI (both user and network side) @@ -37,7 +33,7 @@ #include -static const char* version = "HDLC support module revision 1.11"; +static const char* version = "HDLC support module revision 1.14"; static int hdlc_change_mtu(struct net_device *dev, int new_mtu) @@ -60,7 +56,13 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev) static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p) { - dev_to_hdlc(dev)->netif_rx(skb); + hdlc_device *hdlc = dev_to_hdlc(dev); + if (hdlc->netif_rx) + hdlc->netif_rx(skb); + else { + hdlc->stats.rx_dropped++; /* Shouldn't happen */ + dev_kfree_skb(skb); + } return 0; } @@ -69,6 +71,10 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, #define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS #endif +#ifndef CONFIG_HDLC_RAW_ETH +#define hdlc_raw_eth_ioctl(hdlc, ifr) -ENOSYS +#endif + #ifndef CONFIG_HDLC_PPP #define hdlc_ppp_ioctl(hdlc, ifr) -ENOSYS #endif @@ -96,6 +102,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch(ifr->ifr_settings.type) { case IF_PROTO_HDLC: + case IF_PROTO_HDLC_ETH: case IF_PROTO_PPP: case IF_PROTO_CISCO: case IF_PROTO_FR: @@ -109,6 +116,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch(proto) { case IF_PROTO_HDLC: return hdlc_raw_ioctl(hdlc, ifr); + case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(hdlc, ifr); case IF_PROTO_PPP: return hdlc_ppp_ioctl(hdlc, ifr); case IF_PROTO_CISCO: return hdlc_cisco_ioctl(hdlc, ifr); case IF_PROTO_FR: return hdlc_fr_ioctl(hdlc, ifr); @@ -144,7 +152,6 @@ int register_hdlc_device(hdlc_device *hdlc) if (result != 0) return -EIO; - MOD_INC_USE_COUNT; return 0; } @@ -152,17 +159,17 @@ int register_hdlc_device(hdlc_device *hdlc) void unregister_hdlc_device(hdlc_device *hdlc) { + rtnl_lock(); hdlc_proto_detach(hdlc); - - unregister_netdev(hdlc_to_dev(hdlc)); - MOD_DEC_USE_COUNT; + unregister_netdevice(hdlc_to_dev(hdlc)); + rtnl_unlock(); } MODULE_AUTHOR("Krzysztof Halasa "); MODULE_DESCRIPTION("HDLC support module"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); EXPORT_SYMBOL(hdlc_ioctl); EXPORT_SYMBOL(register_hdlc_device); diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 2e9d40cf9e4d..1d93f3ac14ed 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -2,12 +2,11 @@ * Generic HDLC support routines for Linux * Point-to-point protocol support * - * Copyright (C) 1999 - 2001 Krzysztof Halasa + * Copyright (C) 1999 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. */ #include @@ -68,10 +67,10 @@ static void ppp_close(hdlc_device *hdlc) -static void ppp_rx(struct sk_buff *skb) +static unsigned short ppp_type_trans(struct sk_buff *skb, + struct net_device *dev) { - skb->protocol = htons(ETH_P_WAN_PPP); - netif_rx(skb); + return __constant_htons(ETH_P_WAN_PPP); } @@ -103,7 +102,8 @@ int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc->open = ppp_open; hdlc->stop = ppp_close; - hdlc->netif_rx = ppp_rx; + hdlc->netif_rx = NULL; + hdlc->type_trans = ppp_type_trans; hdlc->proto = IF_PROTO_PPP; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index 66d32beabb5a..7bc89d695ecd 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -2,12 +2,11 @@ * Generic HDLC support routines for Linux * HDLC support * - * Copyright (C) 1999 - 2001 Krzysztof Halasa + * Copyright (C) 1999 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. */ #include @@ -26,10 +25,10 @@ #include -static void raw_rx(struct sk_buff *skb) +static unsigned short raw_type_trans(struct sk_buff *skb, + struct net_device *dev) { - skb->protocol = htons(ETH_P_IP); - netif_rx(skb); + return __constant_htons(ETH_P_IP); } @@ -67,7 +66,7 @@ int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr) new_settings.encoding = ENCODING_NRZ; if (new_settings.parity == PARITY_DEFAULT) - new_settings.parity = PARITY_NONE; + new_settings.parity = PARITY_CRC16_PR1_CCITT; result = hdlc->attach(hdlc, new_settings.encoding, new_settings.parity); @@ -79,11 +78,13 @@ int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc->open = NULL; hdlc->stop = NULL; - hdlc->netif_rx = raw_rx; + hdlc->netif_rx = NULL; + hdlc->type_trans = raw_type_trans; hdlc->proto = IF_PROTO_HDLC; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_RAWHDLC; + dev->flags = IFF_POINTOPOINT | IFF_NOARP; dev->addr_len = 0; return 0; } diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c new file mode 100644 index 000000000000..90c69addb6d5 --- /dev/null +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -0,0 +1,110 @@ +/* + * Generic HDLC support routines for Linux + * HDLC Ethernet emulation support + * + * Copyright (C) 2002-2003 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static int eth_tx(struct sk_buff *skb, struct net_device *dev) +{ + int pad = ETH_ZLEN - skb->len; + if (pad > 0) { /* Pad the frame with zeros */ + int len = skb->len; + if (skb_tailroom(skb) < pad) + if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) { + dev_to_hdlc(dev)->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + skb_put(skb, pad); + memset(skb->data + len, 0, pad); + } + return dev_to_hdlc(dev)->xmit(skb, dev); +} + + +int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr) +{ + raw_hdlc_proto *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; + const size_t size = sizeof(raw_hdlc_proto); + raw_hdlc_proto new_settings; + struct net_device *dev = hdlc_to_dev(hdlc); + int result; + void *old_ch_mtu; + int old_qlen; + + switch (ifr->ifr_settings.type) { + case IF_GET_PROTO: + ifr->ifr_settings.type = IF_PROTO_HDLC_ETH; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) + return -EFAULT; + return 0; + + case IF_PROTO_HDLC_ETH: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (dev->flags & IFF_UP) + return -EBUSY; + + if (copy_from_user(&new_settings, raw_s, size)) + return -EFAULT; + + if (new_settings.encoding == ENCODING_DEFAULT) + new_settings.encoding = ENCODING_NRZ; + + if (new_settings.parity == PARITY_DEFAULT) + new_settings.parity = PARITY_CRC16_PR1_CCITT; + + result = hdlc->attach(hdlc, new_settings.encoding, + new_settings.parity); + if (result) + return result; + + hdlc_proto_detach(hdlc); + memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); + + hdlc->open = NULL; + hdlc->stop = NULL; + hdlc->netif_rx = NULL; + hdlc->type_trans = eth_type_trans; + hdlc->proto = IF_PROTO_HDLC_ETH; + dev->hard_start_xmit = eth_tx; + old_ch_mtu = dev->change_mtu; + old_qlen = dev->tx_queue_len; + ether_setup(dev); + dev->change_mtu = old_ch_mtu; + dev->tx_queue_len = old_qlen; + memcpy(dev->dev_addr, "\x00\x01", 2); + get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); + return 0; + } + + return -EINVAL; +} diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index ff70ac6f1f07..53b118c5f8d5 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -2,12 +2,11 @@ * Generic HDLC support routines for Linux * X.25 support * - * Copyright (C) 1999 - 2001 Krzysztof Halasa + * Copyright (C) 1999 - 2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. */ #include @@ -204,6 +203,7 @@ int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc->open = x25_open; hdlc->stop = x25_close; hdlc->netif_rx = x25_rx; + hdlc->type_trans = NULL; hdlc->proto = IF_PROTO_X25; dev->hard_start_xmit = x25_xmit; dev->hard_header = NULL; diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index ccd5ae7bc62f..939ee3544523 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -1,12 +1,11 @@ /* * SDL Inc. RISCom/N2 synchronous serial card driver for Linux * - * Copyright (C) 1998-2002 Krzysztof Halasa + * Copyright (C) 1998-2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. * * For information see http://hq.pm.waw.pl/hdlc/ * @@ -28,20 +27,28 @@ #include #include #include +#include #include #include #include #include "hd64570.h" -static const char* version = "SDL RISCom/N2 driver version: 1.10"; +static const char* version = "SDL RISCom/N2 driver version: 1.14"; static const char* devname = "RISCom/N2"; #define USE_WINDOWSIZE 16384 #define USE_BUS16BITS 1 #define CLOCK_BASE 9830400 /* 9.8304 MHz */ - +#define MAX_PAGES 16 /* 16 RAM pages at max */ +#define MAX_RAM_SIZE 0x80000 /* 512 KB */ +#if MAX_RAM_SIZE > MAX_PAGES * USE_WINDOWSIZE +#undef MAX_RAM_SIZE +#define MAX_RAM_SIZE (MAX_PAGES * USE_WINDOWSIZE) +#endif #define N2_IOPORTS 0x10 +#define NEED_DETECT_RAM +#define MAX_TX_BUFFERS 10 static char *hw = NULL; /* pointer to hw=xxx command line string */ @@ -86,16 +93,16 @@ typedef struct port_s { struct card_s *card; spinlock_t lock; /* TX lock */ sync_serial_settings settings; + int valid; /* port enabled */ + int rxpart; /* partial frame received, next frame invalid*/ unsigned short encoding; unsigned short parity; + u16 rxin; /* rx ring buffer 'in' pointer */ + u16 txin; /* tx ring buffer 'in' and 'last' pointers */ + u16 txlast; u8 rxs, txs, tmc; /* SCA registers */ - u8 valid; /* port enabled */ u8 phy_node; /* physical port # - 0 or 1 */ u8 log_node; /* logical port # */ - u8 rxin; /* rx ring buffer 'in' pointer */ - u8 txin; /* tx ring buffer 'in' and 'last' pointers */ - u8 txlast; - u8 rxpart; /* partial frame received, next frame invalid*/ }port_t; @@ -106,8 +113,9 @@ typedef struct card_s { u32 ram_size; /* number of bytes */ u16 io; /* IO Base address */ u16 buff_offset; /* offset of first buffer of first channel */ + u16 rx_ring_buffers; /* number of buffers in a ring */ + u16 tx_ring_buffers; u8 irq; /* IRQ (3-15) */ - u8 ring_buffers; /* number of buffers in a ring */ port_t ports[2]; struct card_s *next_card; @@ -209,14 +217,19 @@ static int n2_open(struct net_device *dev) int io = port->card->io; u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0); + + if (!try_module_get(THIS_MODULE)) + return -EFAULT; /* rmmod in progress */ + int result = hdlc_open(hdlc); - if (result) + if (result) { return result; + module_put(THIS_MODULE); + } - MOD_INC_USE_COUNT; mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */ outb(mcr, io + N2_MCR); - + outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */ outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */ sca_open(hdlc); @@ -237,7 +250,7 @@ static int n2_close(struct net_device *dev) mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */ outb(mcr, io + N2_MCR); hdlc_close(hdlc); - MOD_DEC_USE_COUNT; + module_put(THIS_MODULE); return 0; } @@ -297,62 +310,6 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -static u8 n2_count_page(card_t *card) -{ - u8 page; - int i, bcount = USE_WINDOWSIZE, wcount = USE_WINDOWSIZE/2; - u16 *dp = (u16*)card->winbase; - u8 *bp = (u8*)card->winbase; - u8 psr = inb(card->io + N2_PSR) & PSR_WINBITS; - - - for (page = 0; page < 16; page++) { - outb(psr | page, card->io + N2_PSR); /* select a page */ - writeb(page, dp); - if (readb(dp) != page) - break; /* If can't read back, no good memory */ - - outb(psr, card->io + N2_PSR); /* goto page 0 */ - if (readb(dp)) - break; /* If page 0 changed, then wrapped around */ - - outb(psr | page, card->io + N2_PSR); /* select page again */ - - /* first do byte tests */ - for (i = 0; i < bcount; i++) - writeb(i, bp + i); - for (i = 0; i < bcount; i++) - if (readb(bp + i) != (i & 0xff)) - return 0; - - for (i = 0; i < bcount; i++) - writeb(~i, bp + i); - for (i = 0; i < bcount; i++) - if (readb(bp + i) != (~i & 0xff)) - return 0; - - /* next do 16-bit tests */ - for (i = 0; i < wcount; i++) - writew(0x55AA, dp + i); - for (i = 0; i < wcount; i++) - if (readw(dp + i) != 0x55AA) - return 0; - - for (i = 0; i < wcount; i++) - writew(0xAA55, dp + i); - for (i = 0; i < wcount; i++) - if (readw(dp + i) != 0xAA55) - return 0; - - for (i = 0; i < wcount; i++) - writew(page, dp + i); - } - - return page; -} - - - static void n2_destroy_card(card_t *card) { int cnt; @@ -376,11 +333,12 @@ static void n2_destroy_card(card_t *card) -static int n2_run(unsigned long io, unsigned long irq, unsigned long winbase, - long valid0, long valid1) +static int __init n2_run(unsigned long io, unsigned long irq, + unsigned long winbase, long valid0, long valid1) { card_t *card; u8 cnt, pcr; + int i; if (io < 0x200 || io > 0x3FF || (io % N2_IOPORTS) != 0) { printk(KERN_ERR "n2: invalid I/O port value\n"); @@ -391,7 +349,7 @@ static int n2_run(unsigned long io, unsigned long irq, unsigned long winbase, printk(KERN_ERR "n2: invalid IRQ value\n"); return -ENODEV; } - + if (winbase < 0xA0000 || winbase > 0xFFFFF || (winbase & 0xFFF) != 0) { printk(KERN_ERR "n2: invalid RAM value\n"); return -ENODEV; @@ -451,25 +409,27 @@ static int n2_run(unsigned long io, unsigned long irq, unsigned long winbase, pcr = PCR_ENWIN | PCR_VPM | (USE_BUS16BITS ? PCR_BUS16 : 0); outb(pcr, io + N2_PCR); - cnt = n2_count_page(card); - if (!cnt) { - printk(KERN_ERR "n2: memory test failed.\n"); - n2_destroy_card(card); - return -EIO; - } + card->ram_size = sca_detect_ram(card, card->winbase, MAX_RAM_SIZE); - card->ram_size = cnt * USE_WINDOWSIZE; + /* number of TX + RX buffers for one port */ + i = card->ram_size / ((valid0 + valid1) * (sizeof(pkt_desc) + + HDLC_MAX_MRU)); - /* 4 rings required for 2 ports, 2 rings for one port */ - card->ring_buffers = card->ram_size / - ((valid0 + valid1) * 2 * (sizeof(pkt_desc) + HDLC_MAX_MRU)); + card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); + card->rx_ring_buffers = i - card->tx_ring_buffers; - card->buff_offset = (valid0 + valid1) * 2 * (sizeof(pkt_desc)) - * card->ring_buffers; + card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) * + (card->tx_ring_buffers + card->rx_ring_buffers); printk(KERN_DEBUG "n2: RISCom/N2 %u KB RAM, IRQ%u, " - "using %u packets rings\n", card->ram_size / 1024, card->irq, - card->ring_buffers); + "using %u TX + %u RX packets rings\n", card->ram_size / 1024, + card->irq, card->tx_ring_buffers, card->rx_ring_buffers); + + if (card->tx_ring_buffers < 1) { + printk(KERN_ERR "n2: RAM test failed\n"); + n2_destroy_card(card); + return -EIO; + } pcr |= PCR_RUNSCA; /* run SCA */ outb(pcr, io + N2_PCR); @@ -531,7 +491,7 @@ static int __init n2_init(void) return -ENOSYS; /* no parameters specified, abort */ } - printk(KERN_INFO "%s (SCA-%s)\n", version, sca_version); + printk(KERN_INFO "%s\n", version); do { unsigned long io, irq, ram; @@ -558,7 +518,7 @@ static int __init n2_init(void) break; hw++; } - + if (!valid[0] && !valid[1]) break; /* at least one port must be used */ @@ -566,7 +526,7 @@ static int __init n2_init(void) n2_run(io, irq, ram, valid[0], valid[1]); if (*hw == '\x0') - return 0; + return first_card ? 0 : -ENOSYS; }while(*hw++ == ':'); printk(KERN_ERR "n2: invalid hardware parameters\n"); @@ -574,17 +534,6 @@ static int __init n2_init(void) } -#ifndef MODULE -static int __init n2_setup(char *str) -{ - hw = str; - return 1; -} - -__setup("n2=", n2_setup); -#endif - - static void __exit n2_cleanup(void) { card_t *card = first_card; @@ -602,5 +551,5 @@ module_exit(n2_cleanup); MODULE_AUTHOR("Krzysztof Halasa "); MODULE_DESCRIPTION("RISCom/N2 serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_PARM(hw, "s"); /* hw=io,irq,ram,ports:io,irq,... */ +MODULE_LICENSE("GPL v2"); +module_param(hw, charp, 0444); /* hw=io,irq,ram,ports:io,irq,... */ diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index aeceb6f1a7be..6b89e9c85f9b 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -1,12 +1,11 @@ /* * Generic HDLC support routines for Linux * - * Copyright (C) 1999-2002 Krzysztof Halasa + * Copyright (C) 1999-2003 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. */ #ifndef __HDLC_H @@ -52,7 +51,7 @@ #include #define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ -#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */ +#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ #define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */ @@ -145,17 +144,20 @@ typedef struct { typedef struct pvc_device_struct { - struct net_device netdev; /* PVC net device - must be first */ - struct net_device_stats stats; struct hdlc_device_struct *master; - struct pvc_device_struct *next; + struct net_device *main; + struct net_device *ether; /* bridged Ethernet interface */ + struct pvc_device_struct *next; /* Sorted in ascending DLCI order */ + int dlci; + int open_count; struct { - int active; - int new; - int deleted; - int fecn; - int becn; + unsigned int new: 1; + unsigned int active: 1; + unsigned int exist: 1; + unsigned int deleted: 1; + unsigned int fecn: 1; + unsigned int becn: 1; }state; }pvc_device; @@ -180,18 +182,20 @@ typedef struct hdlc_device_struct { void (*stop)(struct hdlc_device_struct *hdlc); void (*proto_detach)(struct hdlc_device_struct *hdlc); void (*netif_rx)(struct sk_buff *skb); + unsigned short (*type_trans)(struct sk_buff *skb, + struct net_device *dev); int proto; /* IF_PROTO_HDLC/CISCO/FR/etc. */ union { struct { fr_proto settings; pvc_device *first_pvc; - int pvc_count; + int dce_pvc_count; struct timer_list timer; int last_poll; int reliable; - int changed; + int dce_changed; int request; int fullrep_sent; u32 last_errors; /* last errors bit list */ @@ -226,6 +230,7 @@ typedef struct hdlc_device_struct { int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr); +int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr); int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr); int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr); int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr); @@ -254,15 +259,9 @@ static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev) } -static __inline__ struct net_device* pvc_to_dev(pvc_device *pvc) -{ - return &pvc->netdev; -} - - static __inline__ pvc_device* dev_to_pvc(struct net_device *dev) { - return (pvc_device*)dev; + return (pvc_device*)dev->priv; } @@ -272,19 +271,6 @@ static __inline__ const char *hdlc_to_name(hdlc_device *hdlc) } -static __inline__ const char *pvc_to_name(pvc_device *pvc) -{ - return pvc_to_dev(pvc)->name; -} - - -static __inline__ u16 netdev_dlci(struct net_device *dev) -{ - return ntohs(*(u16*)dev->dev_addr); -} - - - static __inline__ u16 q922_to_dlci(u8 *hdr) { return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); @@ -345,5 +331,15 @@ static __inline__ void hdlc_proto_detach(hdlc_device *hdlc) } +static __inline__ unsigned short hdlc_type_trans(struct sk_buff *skb, + struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(skb->dev); + if (hdlc->type_trans) + return hdlc->type_trans(skb, dev); + else + return __constant_htons(ETH_P_HDLC); +} + #endif /* __KERNEL */ #endif /* __HDLC_H */ diff --git a/include/linux/hdlc/ioctl.h b/include/linux/hdlc/ioctl.h index c35e1a35d847..78430ba3ea69 100644 --- a/include/linux/hdlc/ioctl.h +++ b/include/linux/hdlc/ioctl.h @@ -33,6 +33,11 @@ typedef struct { unsigned int dlci; } fr_proto_pvc; /* for creating/deleting FR PVCs */ +typedef struct { + unsigned int dlci; + char master[IFNAMSIZ]; /* Name of master FRAD device */ +}fr_proto_pvc_info; /* for returning PVC information only */ + typedef struct { unsigned int interval; unsigned int timeout; @@ -40,16 +45,4 @@ typedef struct { /* PPP doesn't need any info now - supply length = 0 to ioctl */ -union hdlc_settings { - raw_hdlc_proto raw_hdlc; - cisco_proto cisco; - fr_proto fr; - fr_proto_pvc fr_pvc; -}; - -union line_settings { - sync_serial_settings sync; - te1_settings te1; -}; - #endif /* __HDLC_IOCTL_H__ */ diff --git a/include/linux/if.h b/include/linux/if.h index 898cfdf1bb14..c4c72e790700 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -21,6 +21,8 @@ #include /* for "__kernel_caddr_t" et al */ #include /* for "struct sockaddr" et al */ + +#define IFNAMSIZ 16 #include /* Standard interface flags (netdevice->flags). */ @@ -69,7 +71,11 @@ #define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */ #define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */ #define IF_PROTO_X25 0x2006 /* X.25 */ - +#define IF_PROTO_HDLC_ETH 0x2007 /* raw HDLC, Ethernet emulation */ +#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /* Create FR Ethernet-bridged PVC */ +#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /* Delete FR Ethernet-bridged PVC */ +#define IF_PROTO_FR_PVC 0x200A /* for reading PVC status */ +#define IF_PROTO_FR_ETH_PVC 0x200B /* @@ -103,6 +109,7 @@ struct if_settings cisco_proto *cisco; fr_proto *fr; fr_proto_pvc *fr_pvc; + fr_proto_pvc_info *fr_pvc_info; /* interface settings */ sync_serial_settings *sync; @@ -120,7 +127,6 @@ struct if_settings struct ifreq { #define IFHWADDRLEN 6 -#define IFNAMSIZ 16 union { char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ -- cgit v1.2.3 From ec059472a57fdabbac0d4e0e89a3b9547f88d62b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 8 Apr 2003 04:23:03 +0200 Subject: Prepare for the introduction of NFSv4 state code. Split out the open() method for regular files from that of directories. --- fs/nfs/dir.c | 23 ++++++++++++++++++++++- fs/nfs/file.c | 27 ++++++++++++++++++++++++++- fs/nfs/inode.c | 12 +----------- fs/nfs/nfs4proc.c | 11 +++++++++++ include/linux/nfs_xdr.h | 1 + 5 files changed, 61 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index cc35ed0b91e1..c9e533fca55e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -35,6 +35,7 @@ #define NFS_PARANOIA 1 /* #define NFS_DEBUG_VERBOSE 1 */ +static int nfs_opendir(struct inode *, struct file *); static int nfs_readdir(struct file *, void *, filldir_t); static struct dentry *nfs_lookup(struct inode *, struct dentry *); static int nfs_cached_lookup(struct inode *, struct dentry *, @@ -52,7 +53,7 @@ static int nfs_rename(struct inode *, struct dentry *, struct file_operations nfs_dir_operations = { .read = generic_read_dir, .readdir = nfs_readdir, - .open = nfs_open, + .open = nfs_opendir, .release = nfs_release, }; @@ -71,6 +72,26 @@ struct inode_operations nfs_dir_inode_operations = { .setattr = nfs_setattr, }; +/* + * Open file + */ +static int +nfs_opendir(struct inode *inode, struct file *filp) +{ + struct nfs_server *server = NFS_SERVER(inode); + int res = 0; + + lock_kernel(); + /* Do cto revalidation */ + if (server->flags & NFS_MOUNT_NOCTO) + res = __nfs_revalidate_inode(server, inode); + /* Call generic open code in order to cache credentials */ + if (!res) + res = nfs_open(inode, filp); + unlock_kernel(); + return res; +} + typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int); typedef struct { struct file *file; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 40746348c9d8..66ea5fdaa9d0 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -34,6 +34,7 @@ #define NFSDBG_FACILITY NFSDBG_FILE +static int nfs_file_open(struct inode *, struct file *); static int nfs_file_mmap(struct file *, struct vm_area_struct *); static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); static ssize_t nfs_file_read(struct kiocb *, char *, size_t, loff_t); @@ -48,7 +49,7 @@ struct file_operations nfs_file_operations = { .aio_read = nfs_file_read, .aio_write = nfs_file_write, .mmap = nfs_file_mmap, - .open = nfs_open, + .open = nfs_file_open, .flush = nfs_file_flush, .release = nfs_release, .fsync = nfs_fsync, @@ -67,6 +68,30 @@ struct inode_operations nfs_file_inode_operations = { # define IS_SWAPFILE(inode) (0) #endif +/* + * Open file + */ +static int +nfs_file_open(struct inode *inode, struct file *filp) +{ + struct nfs_server *server = NFS_SERVER(inode); + int (*open)(struct inode *, struct file *); + int res = 0; + + lock_kernel(); + /* Do NFSv4 open() call */ + if ((open = server->rpc_ops->file_open) != NULL) + res = open(inode, filp); + /* Do cto revalidation */ + else if (server->flags & NFS_MOUNT_NOCTO) + res = __nfs_revalidate_inode(server, inode); + /* Call generic open code in order to cache credentials */ + if (!res) + res = nfs_open(inode, filp); + unlock_kernel(); + return res; +} + /* * Flush all dirty pages, and check for write errors. * diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 67ed9d1bc1b8..1c7b45be7358 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -855,23 +855,13 @@ int nfs_open(struct inode *inode, struct file *filp) { struct rpc_auth *auth; struct rpc_cred *cred; - int err = 0; - lock_kernel(); - /* Ensure that we revalidate the data cache */ - if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOCTO) { - err = __nfs_revalidate_inode(NFS_SERVER(inode),inode); - if (err) - goto out; - } auth = NFS_CLIENT(inode)->cl_auth; cred = rpcauth_lookupcred(auth, 0); filp->private_data = cred; if (filp->f_mode & FMODE_WRITE) nfs_set_mmcred(inode, cred); -out: - unlock_kernel(); - return err; + return 0; } int nfs_release(struct inode *inode, struct file *filp) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 317a8bb269d9..ccbca9dace46 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1560,6 +1560,16 @@ nfs4_proc_renew(struct nfs_server *server) return rpc_execute(task); } +/* +* To be changed into a real NFSv4 file_open soon. +*/ + +int +nfs4_proc_file_open(struct inode *inode, struct file *filp) +{ + return 0; +} + struct nfs_rpc_ops nfs_v4_clientops = { .version = 4, /* protocol version */ .getroot = nfs4_proc_get_root, @@ -1589,6 +1599,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { .read_setup = nfs4_proc_read_setup, .write_setup = nfs4_proc_write_setup, .commit_setup = nfs4_proc_commit_setup, + .file_open = nfs4_proc_file_open, }; /* diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 2b96e1e5aa97..980705c7307e 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -597,6 +597,7 @@ struct nfs_rpc_ops { void (*read_setup) (struct nfs_read_data *, unsigned int count); void (*write_setup) (struct nfs_write_data *, unsigned int count, int how); void (*commit_setup) (struct nfs_write_data *, u64 start, u32 len, int how); + int (*file_open) (struct inode *, struct file *); }; /* -- cgit v1.2.3 From 62175be2bd850d3c2db5065fb3ef4dff3272c068 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 8 Apr 2003 04:26:25 +0200 Subject: Implement stateful open() for NFSv4 as per RFC3010-bis. The resulting state is saved in the NFS-specific part of the struct inode. Initially we just start with 3 possible states: - open for read - open for write - open for read/write --- fs/nfs/inode.c | 14 +++ fs/nfs/nfs4proc.c | 289 +++++++++++++++++++++++++++---------------- fs/nfs/nfs4state.c | 174 ++++++++++++++++++++++++-- fs/nfs/nfs4xdr.c | 316 ++++++++++++++++++++++++++++++++++++------------ include/linux/nfs4.h | 2 + include/linux/nfs_fs.h | 72 +++++++++-- include/linux/nfs_xdr.h | 45 +++++++ 7 files changed, 708 insertions(+), 204 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 1c7b45be7358..2e8d2e1daeec 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -140,6 +140,10 @@ nfs_clear_inode(struct inode *inode) cred = nfsi->cache_access.cred; if (cred) put_rpccred(cred); + /* Clean up the V4 state */ + nfs4_put_shareowner(inode, nfsi->wo_owner); + nfs4_put_shareowner(inode, nfsi->ro_owner); + nfs4_put_shareowner(inode, nfsi->rw_owner); } void @@ -1492,9 +1496,18 @@ static struct file_system_type nfs4_fs_type = { .kill_sb = nfs_kill_super, .fs_flags = FS_ODD_RENAME, }; + +#define nfs4_zero_state(nfsi) \ + do { \ + (nfsi)->wo_owner = NULL; \ + (nfsi)->ro_owner = NULL; \ + (nfsi)->rw_owner = NULL; \ + } while(0) #define register_nfs4fs() register_filesystem(&nfs4_fs_type) #define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type) #else +#define nfs4_zero_state(nfsi) \ + do { } while (0) #define register_nfs4fs() (0) #define unregister_nfs4fs() #endif @@ -1516,6 +1529,7 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) return NULL; nfsi->flags = 0; nfsi->mm_cred = NULL; + nfs4_zero_state(nfsi); return &nfsi->vfs_inode; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ccbca9dace46..15ce5d40f2c2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -346,48 +346,6 @@ nfs4_setup_putrootfh(struct nfs4_compound *cp) cp->req_nops++; } -static void -nfs4_setup_open(struct nfs4_compound *cp, int flags, struct qstr *name, - struct iattr *sattr, char *stateid, struct nfs4_change_info *cinfo, - u32 *rflags) -{ - struct nfs4_open *open = GET_OP(cp, open); - - BUG_ON(cp->flags); - - open->op_client_state = cp->server->nfs4_state; - open->op_share_access = flags & 3; - open->op_opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE; - open->op_createmode = NFS4_CREATE_UNCHECKED; - open->op_attrs = sattr; - if (flags & O_EXCL) { - u32 *p = (u32 *) open->op_verifier; - p[0] = jiffies; - p[1] = current->pid; - open->op_createmode = NFS4_CREATE_EXCLUSIVE; - } - open->op_name = name; - open->op_stateid = stateid; - open->op_cinfo = cinfo; - open->op_rflags = rflags; - - OPNUM(cp) = OP_OPEN; - cp->req_nops++; - cp->renew_index = cp->req_nops; -} - -static void -nfs4_setup_open_confirm(struct nfs4_compound *cp, char *stateid) -{ - struct nfs4_open_confirm *open_confirm = GET_OP(cp, open_confirm); - - open_confirm->oc_stateid = stateid; - - OPNUM(cp) = OP_OPEN_CONFIRM; - cp->req_nops++; - cp->renew_index = cp->req_nops; -} - static void nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier, struct page **pages, unsigned int bufsize, struct dentry *dentry) @@ -626,44 +584,114 @@ process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr) } } -static int -do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, - struct nfs_fattr *fattr, struct nfs_fh *fhandle, u32 *seqid, char *stateid) -{ - struct nfs4_compound compound; - struct nfs4_op ops[7]; - struct nfs4_change_info dir_cinfo; - struct nfs_fattr dir_attr; - u32 dir_bmres[2]; - u32 bmres[2]; - u32 rflags; - int status; - - dir_attr.valid = 0; - fattr->valid = 0; - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "open"); - nfs4_setup_putfh(&compound, NFS_FH(dir)); - nfs4_setup_savefh(&compound); - nfs4_setup_open(&compound, flags, name, sattr, stateid, &dir_cinfo, &rflags); - nfs4_setup_getattr(&compound, fattr, bmres); - nfs4_setup_getfh(&compound, fhandle); - nfs4_setup_restorefh(&compound); - nfs4_setup_getattr(&compound, &dir_attr, dir_bmres); - if ((status = nfs4_call_compound(&compound, NULL, 0))) - return status; +int +nfs4_do_open(struct inode *dir, struct qstr *name, int flags, + struct iattr *sattr, struct nfs_fattr *fattr, + struct nfs_fh *fhandle, struct nfs4_shareowner **spp) +{ + struct nfs4_shareowner *sp; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs4_change_info d_cinfo; + int status; + u32 f_bmres[2]; + u32 d_bmres[2]; + struct nfs_fattr d_attr = { + .valid 0, + }; + struct nfs_fattr f_attr = { + .valid 0, + }; + struct nfs4_getattr f_getattr = { + .gt_bmval = nfs4_fattr_bitmap, + .gt_attrs = (fattr == NULL ? &f_attr: fattr), + .gt_bmres = f_bmres, + }; + struct nfs4_getattr d_getattr = { + .gt_bmval = nfs4_fattr_bitmap, + .gt_attrs = &d_attr, + .gt_bmres = d_bmres, + }; + struct nfs_openargs o_arg = { + .fh = NFS_FH(dir), + .share_access = flags & O_ACCMODE, + .clientid = NFS_SERVER(dir)->nfs4_state->cl_clientid, + .opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE, + .createmode = (flags & O_EXCL) ? NFS4_CREATE_EXCLUSIVE : NFS4_CREATE_UNCHECKED, + .name = name, + .f_getattr = &f_getattr, + .d_getattr = &d_getattr, + }; + struct nfs_openres o_res = { + .cinfo = &d_cinfo, + .f_getattr = &f_getattr, + .d_getattr = &d_getattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], + .rpc_argp = &o_arg, + .rpc_resp = &o_res, + }; - process_cinfo(&dir_cinfo, &dir_attr); - nfs_refresh_inode(dir, &dir_attr); - if (!(rflags & NFS4_OPEN_RESULT_CONFIRM)) { - *seqid = 1; - return 0; + status = -ENOMEM; + if (!(sp = nfs4_get_shareowner(dir))) { + dprintk("nfs4_do_open: nfs4_get_shareowner failed!\n"); + goto out; + } + if (o_arg.createmode & NFS4_CREATE_EXCLUSIVE){ + u32 *p = (u32 *) o_arg.u.verifier; + p[0] = jiffies; + p[1] = current->pid; + } else if (o_arg.createmode == NFS4_CREATE_UNCHECKED) { + o_arg.u.attrs = sattr; + } + /* Serialization for the sequence id */ + down(&sp->so_sema); + o_arg.seqid = sp->so_seqid; + o_arg.id = sp->so_id; + + status = rpc_call_sync(server->client, &msg, 0); + if (status) { + goto out_up; + } + nfs4_increment_seqid(status, sp); + process_cinfo(&d_cinfo, &d_attr); + nfs_refresh_inode(dir, &d_attr); + + if (fhandle) { + memset(fhandle, 0, sizeof(*fhandle)); + fhandle->size = (o_res.fh.size < NFS_MAXFHSIZE ? o_res.fh.size : NFS_MAXFHSIZE); + memcpy(fhandle->data, o_res.fh.data, fhandle->size); } - *seqid = 2; - nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "open_confirm"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_open_confirm(&compound, stateid); - return nfs4_call_compound(&compound, NULL, 0); + if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) { + struct nfs_open_confirmargs oc_arg = { + .fh = &o_res.fh, + .seqid = sp->so_seqid, + }; + struct nfs_open_confirmres oc_res = { + .status = 0, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], + .rpc_argp = &oc_arg, + .rpc_resp = &oc_res, + }; + + memcpy(oc_arg.stateid, o_res.stateid, sizeof(nfs4_stateid)); + status = rpc_call_sync(server->client, &msg, 0); + if (status) + goto out_up; + nfs4_increment_seqid(status, sp); + memcpy(sp->so_stateid, oc_res.stateid, sizeof(nfs4_stateid)); + } else + memcpy(sp->so_stateid, o_res.stateid, sizeof(nfs4_stateid)); + sp->so_flags = flags & O_ACCMODE; + +out_up: + up(&sp->so_sema); +out: + *spp = sp; + return status; } static int @@ -799,19 +827,19 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct inode * inode = dentry->d_inode; int size_change = sattr->ia_valid & ATTR_SIZE; struct nfs_fh throwaway_fh; - u32 seqid; - nfs4_stateid stateid; - int status; + struct nfs4_shareowner *sp = NULL; + int status, fake = 1; fattr->valid = 0; if (size_change) { - status = do_open(dentry->d_parent->d_inode, &dentry->d_name, - NFS4_SHARE_ACCESS_WRITE, NULL, fattr, - &throwaway_fh, &seqid, stateid); + status = nfs4_do_open(dentry->d_parent->d_inode, + &dentry->d_name, + O_WRONLY, NULL, fattr, + &throwaway_fh,&sp); if (status) return status; - + fake = 0; /* * Because OPEN is always done by name in nfsv4, it is * possible that we opened a different file by the same @@ -823,16 +851,15 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, */ if (fattr->fileid != NFS_FILEID(inode)) { printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n"); - do_close(NFS_SERVER(inode), NFS_FH(inode), seqid, stateid); + do_close(NFS_SERVER(inode), NFS_FH(inode), sp->so_seqid, sp->so_stateid); return -EIO; } } - else - memcpy(stateid, zero_stateid, sizeof(nfs4_stateid)); - status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr, stateid); + status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr, + fake == 1? zero_stateid: sp->so_stateid); if (size_change) - do_close(NFS_SERVER(inode), NFS_FH(inode), seqid, stateid); + do_close(NFS_SERVER(inode), NFS_FH(inode), sp->so_seqid, sp->so_stateid); return status; } @@ -1025,21 +1052,38 @@ nfs4_proc_write(struct inode *inode, struct rpc_cred *cred, return rpc_call_sync(server->client, &msg, rpcflags); } +/* + * Got race? + * We will need to arrange for the VFS layer to provide an atomic open. + * Until then, this create/open method is prone to inefficiency and race + * conditions due to the lookup, create, and open VFS calls from sys_open() + * placed on the wire. + * + * Given the above sorry state of affairs, I'm simply sending an OPEN, a + * possible SETATTR, and then a CLOSE + * The file will be opened again in the subsequent VFS open call + * (nfs4_proc_file_open). + * + * The open for read will just hang around to be used by any process that + * opens the file O_RDONLY. This will all be resolved with the VFS changes. + */ + static int nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, - int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr) + int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - int oflags; - u32 seqid; - nfs4_stateid stateid; - int status; + int oflags; + struct nfs4_shareowner *sp = NULL; + int status; - oflags = NFS4_SHARE_ACCESS_READ | O_CREAT | (flags & O_EXCL); - status = do_open(dir, name, oflags, sattr, fattr, fhandle, &seqid, stateid); + oflags = O_RDONLY | O_CREAT | (flags & O_EXCL); + status = nfs4_do_open(dir, name, oflags, sattr, fattr, fhandle, &sp); if (!status) { - if (flags & O_EXCL) - status = do_setattr(NFS_SERVER(dir), fattr, fhandle, sattr, stateid); - do_close(NFS_SERVER(dir), fhandle, seqid, stateid); + if (flags & O_EXCL) { + status = do_setattr(NFS_SERVER(dir), fattr, + fhandle, sattr, sp->so_stateid); + /* XXX should i bother closing the file? */ + } } return status; } @@ -1561,15 +1605,54 @@ nfs4_proc_renew(struct nfs_server *server) } /* -* To be changed into a real NFSv4 file_open soon. -*/ - + * We will need to arrange for the VFS layer to provide an atomic open. + * Until then, this open method is prone to inefficiency and race conditions + * due to the lookup, potential create, and open VFS calls from sys_open() + * placed on the wire. + */ int nfs4_proc_file_open(struct inode *inode, struct file *filp) { - return 0; + struct dentry *dentry = filp->f_dentry; + struct inode *dir = dentry->d_parent->d_inode; + int flags, status = 0; + + dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n", + (int)dentry->d_parent->d_name.len, + dentry->d_parent->d_name.name, + (int)dentry->d_name.len, dentry->d_name.name); + + lock_kernel(); + + /* isn't this done in open_namei? */ + if (!S_ISREG(inode->i_mode)) { + status = -EISDIR; + goto out; + } + + flags = filp->f_flags & O_ACCMODE; + +/* +* Got race?? +* We have already opened the file "O_EXCL" in nfs4_proc_create!! +* This ugliness will go away with lookup-intent... +*/ + while (!nfs4_get_inode_share(inode, flags)) { + struct nfs4_shareowner *sp = NULL; + status = nfs4_do_open(dir, &dentry->d_name, flags, NULL, NULL, NULL, &sp); + if (status) { + nfs4_put_shareowner(inode,sp); + break; + } + if (nfs4_set_inode_share(inode, sp, flags)) + nfs4_put_shareowner(inode,sp); + } +out: + unlock_kernel(); + return status; } + struct nfs_rpc_ops nfs_v4_clientops = { .version = 4, /* protocol version */ .getroot = nfs4_proc_get_root, diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index ecbc54fb1048..059880274526 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -42,6 +42,16 @@ #include #include +/* This protects most of the client-side state. */ +static spinlock_t state_spinlock = SPIN_LOCK_UNLOCKED; + +nfs4_stateid zero_stateid = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +nfs4_stateid one_stateid = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + /* * nfs4_get_client(): returns an empty client structure * nfs4_put_client(): drops reference to client structure @@ -52,26 +62,164 @@ struct nfs4_client * nfs4_get_client(void) { - struct nfs4_client *clp; + struct nfs4_client *clp; - if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL))) { - atomic_set(&clp->cl_count, 1); - clp->cl_clientid = 0; - INIT_LIST_HEAD(&clp->cl_lockowners); - } - return clp; + if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL))) + memset(clp, 0, sizeof(nfs4_verifier)); + return clp; } void nfs4_put_client(struct nfs4_client *clp) { - BUG_ON(!clp); - BUG_ON(!atomic_read(&clp->cl_count)); - - if (atomic_dec_and_test(&clp->cl_count)) { - BUG_ON(!list_empty(&clp->cl_lockowners)); - kfree(clp); + BUG_ON(!clp); + kfree(clp); +} + +static inline u32 +nfs4_alloc_lockowner_id(struct nfs4_client *clp) +{ + u32 res; + + spin_lock(&state_spinlock); + res = clp->cl_lockowner_id ++; + spin_unlock(&state_spinlock); + return res; +} + +/* + * nfs4_get_shareowner(): this is called on the OPEN or CREATE path to + * obtain a new shareowner. + * + * There are three shareowners (open_owner4 in rfc3010) per inode, + * one for each possible combination of share lock access. Since + * Linux does not support the deny access type, there are + * three (not 9) referenced by the nfs_inode: + * + * O_WRONLY: inode->wo_owner + * O_RDONLY: inode->ro_owner + * O_RDWR: inode->rw_owner + * + * We create a new shareowner the first time a file is OPENed with + * one of the above shares. All other OPENs with a similar + * share use the single stateid associated with the inode. + * + */ +struct nfs4_shareowner * +nfs4_get_shareowner(struct inode *dir) +{ + struct nfs4_client *clp; + struct nfs4_shareowner *sp; + + sp = kmalloc(sizeof(*sp),GFP_KERNEL); + if (!sp) + return NULL; + clp = (NFS_SB(dir->i_sb))->nfs4_state; + BUG_ON(!clp); + init_MUTEX(&sp->so_sema); + sp->so_seqid = 0; /* arbitrary */ + memset(sp->so_stateid, 0, sizeof(nfs4_stateid)); + sp->so_id = nfs4_alloc_lockowner_id(clp); + return sp; +} + +/* + * Called for each inode shareowner in nfs_clear_inode, + * or if nfs4_do_open fails. + */ +void +nfs4_put_shareowner(struct inode *inode, struct nfs4_shareowner *sp) +{ + if (!sp) + return; + kfree(sp); +} + +/* +* Called with sp->so_sema held. +* +* Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or +* failed with a seqid incrementing error - +* see comments nfs_fs.h:seqid_mutating_error() +*/ +void +nfs4_increment_seqid(u32 status, struct nfs4_shareowner *sp) +{ + if (status == NFS_OK || seqid_mutating_err(status)) + sp->so_seqid++; +} + +/* +* Called by nfs4_proc_open to set the appropriate stateid +*/ +int +nfs4_set_inode_share(struct inode * inode, struct nfs4_shareowner *sp, unsigned int open_flags) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + switch (open_flags & O_ACCMODE) { + case O_RDONLY: + if (!nfsi->ro_owner) { + nfsi->ro_owner = sp; + return 0; + } + break; + case O_WRONLY: + if (!nfsi->wo_owner) { + nfsi->wo_owner = sp; + return 0; + } + break; + case O_RDWR: + if (!nfsi->rw_owner) { + nfsi->rw_owner = sp; + return 0; + } + } + return -EBUSY; +} + +/* +* Boolean test to determine if an OPEN call goes on the wire. +* +* Called by nfs4_proc_open. +*/ +int +nfs4_test_shareowner(struct inode *inode, unsigned int open_flags) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + switch (open_flags & O_ACCMODE) { + case O_RDONLY: + if(nfsi->ro_owner) + return 0; + break; + case O_WRONLY: + if(nfsi->wo_owner) + return 0; + break; + case O_RDWR: + if(nfsi->rw_owner) + return 0; } + return 1; +} + +struct nfs4_shareowner * +nfs4_get_inode_share(struct inode * inode, unsigned int open_flags) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + switch (open_flags & O_ACCMODE) { + case O_RDONLY: + return nfsi->ro_owner; + case O_WRONLY: + return nfsi->wo_owner; + case O_RDWR: + return nfsi->rw_owner; + } + /* Duh gcc warning if we don't... */ + return NULL; } /* diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index df753fc10ff4..319d16b0bd01 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -72,6 +72,17 @@ extern int nfs_stat_to_errno(int); #define encode_putfh_maxsz op_encode_hdr_maxsz + 1 + \ (NFS4_FHSIZE >> 2) #define decode_putfh_maxsz op_decode_hdr_maxsz +#define encode_getfh_maxsz op_encode_hdr_maxsz +#define decode_getfh_maxsz op_decode_hdr_maxsz + 1 + \ + (NFS4_FHSIZE >> 2) +#define encode_getattr_maxsz op_encode_hdr_maxsz + 3 +#define nfs4_fattr_bitmap_maxsz 26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2) +#define decode_getattr_maxsz op_decode_hdr_maxsz + 3 + \ + nfs4_fattr_bitmap_maxsz +#define encode_savefh_maxsz op_encode_hdr_maxsz +#define decode_savefh_maxsz op_decode_hdr_maxsz +#define encode_restorefh_maxsz op_encode_hdr_maxsz +#define decode_restorefh_maxsz op_decode_hdr_maxsz #define encode_read_getattr_maxsz op_encode_hdr_maxsz + 2 #define decode_read_getattr_maxsz op_decode_hdr_maxsz + 8 #define encode_pre_write_getattr_maxsz op_encode_hdr_maxsz + 2 @@ -109,6 +120,31 @@ extern int nfs_stat_to_errno(int); decode_pre_write_getattr_maxsz + \ op_decode_hdr_maxsz + 2 + \ decode_post_write_getattr_maxsz +#define NFS4_enc_open_sz compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_savefh_maxsz + \ + op_encode_hdr_maxsz + \ + 13 + 3 + 2 + 64 + \ + encode_getattr_maxsz + \ + encode_getfh_maxsz + \ + encode_restorefh_maxsz + \ + encode_getattr_maxsz +#define NFS4_dec_open_sz compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + decode_savefh_maxsz + \ + op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \ + decode_getattr_maxsz + \ + decode_getfh_maxsz + \ + decode_restorefh_maxsz + \ + decode_getattr_maxsz +#define NFS4_enc_open_confirm_sz \ + compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz + 5 +#define NFS4_dec_open_confirm_sz compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 4 + static struct { @@ -503,69 +539,76 @@ encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup) } static int -encode_open(struct xdr_stream *xdr, struct nfs4_open *open) +encode_open(struct xdr_stream *xdr, struct nfs_openargs *arg) { - static int global_id = 0; - int id = global_id++; int status; uint32_t *p; - - /* seqid, share_access, share_deny, clientid, ownerlen, owner, opentype */ + + /* + * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, + * owner 4, opentype 4 = 36 + */ RESERVE_SPACE(36); WRITE32(OP_OPEN); - WRITE32(0); /* seqid */ - WRITE32(open->op_share_access); - WRITE32(0); /* for us, share_deny== 0 always */ - WRITE64(open->op_client_state->cl_clientid); + WRITE32(arg->seqid); + switch (arg->share_access) { + case O_RDONLY: + WRITE32(NFS4_SHARE_ACCESS_READ); + break; + case O_WRONLY: + WRITE32(NFS4_SHARE_ACCESS_WRITE); + break; + case O_RDWR: + WRITE32(NFS4_SHARE_ACCESS_BOTH); + } + WRITE32(0); /* for linux, share_deny = 0 always */ + WRITE64(arg->clientid); WRITE32(4); - WRITE32(id); - WRITE32(open->op_opentype); - - if (open->op_opentype == NFS4_OPEN_CREATE) { - if (open->op_createmode == NFS4_CREATE_EXCLUSIVE) { - RESERVE_SPACE(4+sizeof(nfs4_verifier)); - WRITE32(open->op_createmode); - WRITEMEM(open->op_verifier, sizeof(nfs4_verifier)); + WRITE32(arg->id); + WRITE32(arg->opentype); + + if (arg->opentype == NFS4_OPEN_CREATE) { + if (arg->createmode == NFS4_CREATE_EXCLUSIVE) { + RESERVE_SPACE(12); + WRITE32(arg->createmode); + WRITEMEM(arg->u.verifier, sizeof(nfs4_verifier)); } - else if (open->op_attrs) { + else if (arg->u.attrs) { RESERVE_SPACE(4); - WRITE32(open->op_createmode); - if ((status = encode_attrs(xdr, open->op_attrs))) + WRITE32(arg->createmode); + if ((status = encode_attrs(xdr, arg->u.attrs))) return status; } else { RESERVE_SPACE(12); - WRITE32(open->op_createmode); + WRITE32(arg->createmode); WRITE32(0); WRITE32(0); } } - RESERVE_SPACE(8 + open->op_name->len); + RESERVE_SPACE(8 + arg->name->len); WRITE32(NFS4_OPEN_CLAIM_NULL); - WRITE32(open->op_name->len); - WRITEMEM(open->op_name->name, open->op_name->len); - + WRITE32(arg->name->len); + WRITEMEM(arg->name->name, arg->name->len); + return 0; } static int -encode_open_confirm(struct xdr_stream *xdr, struct nfs4_open_confirm *open_confirm) +encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg) { uint32_t *p; - /* - * Note: In this "stateless" implementation, the OPEN_CONFIRM - * seqid is always equal to 1. - */ RESERVE_SPACE(8+sizeof(nfs4_stateid)); WRITE32(OP_OPEN_CONFIRM); - WRITEMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid)); - WRITE32(1); - + WRITEMEM(arg->stateid, sizeof(nfs4_stateid)); + WRITE32(arg->seqid); + return 0; } + static int encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh) { @@ -833,12 +876,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_LOOKUP: status = encode_lookup(xdr, &cp->ops[i].u.lookup); break; - case OP_OPEN: - status = encode_open(xdr, &cp->ops[i].u.open); - break; - case OP_OPEN_CONFIRM: - status = encode_open_confirm(xdr, &cp->ops[i].u.open_confirm); - break; case OP_PUTFH: status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle); break; @@ -903,6 +940,65 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *c cp->timestamp = jiffies; return status; } +/* + * Encode an OPEN request + */ +static int +nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 7, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if (status) + goto out; + status = encode_savefh(&xdr); + if (status) + goto out; + status = encode_open(&xdr,args); + if (status) + goto out; + status = encode_getattr(&xdr, args->f_getattr); + if (status) + goto out; + status = encode_getfh(&xdr); + if (status) + goto out; + status = encode_restorefh(&xdr); + if (status) + goto out; + status = encode_getattr(&xdr, args->d_getattr); +out: + return status; +} + +/* + * Encode an OPEN_CONFIRM request + */ +static int +nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_open_confirm(&xdr, args); +out: + return status; +} + /* * Encode a READ request @@ -968,7 +1064,7 @@ out: } /* - * Encode a COMMIT request + * a COMMIT request */ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) @@ -1611,49 +1707,49 @@ decode_lookup(struct xdr_stream *xdr) } static int -decode_open(struct xdr_stream *xdr, struct nfs4_open *open) +decode_open(struct xdr_stream *xdr, struct nfs_openres *res) { - uint32_t *p; - uint32_t bmlen, delegation_type; - int status; - - status = decode_op_hdr(xdr, OP_OPEN); - if (status) - return status; - READ_BUF(sizeof(nfs4_stateid)); - COPYMEM(open->op_stateid, sizeof(nfs4_stateid)); + uint32_t *p; + uint32_t bmlen, delegation_type; + int status; - decode_change_info(xdr, open->op_cinfo); + status = decode_op_hdr(xdr, OP_OPEN); + if (status) + return status; + READ_BUF(sizeof(nfs4_stateid)); + COPYMEM(res->stateid, sizeof(nfs4_stateid)); - READ_BUF(8); - READ32(*open->op_rflags); - READ32(bmlen); - if (bmlen > 10) - goto xdr_error; - - READ_BUF((bmlen << 2) + 4); - p += bmlen; - READ32(delegation_type); - if (delegation_type != NFS4_OPEN_DELEGATE_NONE) - goto xdr_error; - - DECODE_TAIL; + decode_change_info(xdr, res->cinfo); + + READ_BUF(8); + READ32(res->rflags); + READ32(bmlen); + if (bmlen > 10) + goto xdr_error; + + READ_BUF((bmlen << 2) + 4); + p += bmlen; + READ32(delegation_type); + if (delegation_type != NFS4_OPEN_DELEGATE_NONE) + goto xdr_error; + + DECODE_TAIL; } static int -decode_open_confirm(struct xdr_stream *xdr, struct nfs4_open_confirm *open_confirm) +decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) { - uint32_t *p; - int status; + uint32_t *p; - status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); - if (status) - return status; - READ_BUF(sizeof(nfs4_stateid)); - COPYMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid)); - return 0; + res->status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); + if (res->status) + return res->status; + READ_BUF(sizeof(nfs4_stateid)); + COPYMEM(res->stateid, sizeof(nfs4_stateid)); + return 0; } + static int decode_putfh(struct xdr_stream *xdr) { @@ -1998,12 +2094,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_LOOKUP: status = decode_lookup(xdr); break; - case OP_OPEN: - status = decode_open(xdr, &op->u.open); - break; - case OP_OPEN_CONFIRM: - status = decode_open_confirm(xdr, &op->u.open_confirm); - break; case OP_PUTFH: status = decode_putfh(xdr); break; @@ -2075,6 +2165,72 @@ out: return status; } + +/* + * Decode OPEN response + */ +static int +nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + struct nfs4_getfh gfh = { + .gf_fhandle = &res->fh, + }; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_savefh(&xdr); + if (status) + goto out; + status = decode_open(&xdr, res); + if (status) + goto out; + status = decode_getattr(&xdr, res->f_getattr); + if (status) + goto out; + status = decode_getfh(&xdr, &gfh); + if (status) + goto out; + status = decode_restorefh(&xdr); + if (status) + goto out; + status = decode_getattr(&xdr, res->d_getattr); + if (status) + goto out; +out: + return status; +} + +/* + * Decode OPEN_CONFIRM response + */ +static int +nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_open_confirm(&xdr, res); +out: + return status; +} + + /* * Decode Read response */ @@ -2216,6 +2372,8 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(READ, enc_read, dec_read), PROC(WRITE, enc_write, dec_write), PROC(COMMIT, enc_commit, dec_commit), + PROC(OPEN, enc_open, dec_open), + PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 7c0d596db02f..02c77391d6f8 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -206,6 +206,8 @@ enum { NFSPROC4_CLNT_READ, NFSPROC4_CLNT_WRITE, NFSPROC4_CLNT_COMMIT, + NFSPROC4_CLNT_OPEN, + NFSPROC4_CLNT_OPEN_CONFIRM, }; #endif diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index bc44563921f7..7d53fd8a8710 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -155,6 +155,13 @@ struct nfs_inode { wait_queue_head_t nfs_i_wait; +#ifdef CONFIG_NFS_V4 + /* NFSv4 state */ + struct nfs4_shareowner *ro_owner; + struct nfs4_shareowner *wo_owner; + struct nfs4_shareowner *rw_owner; +#endif /* CONFIG_NFS_V4*/ + struct inode vfs_inode; }; @@ -435,28 +442,74 @@ extern void * nfs_root_data(void); #define NFS_JUKEBOX_RETRY_TIME (5 * HZ) #ifdef CONFIG_NFS_V4 + +/* + * In a seqid-mutating op, this macro controls which error return + * values trigger incrementation of the seqid. + * + * from rfc 3010: + * The client MUST monotonically increment the sequence number for the + * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE + * operations. This is true even in the event that the previous + * operation that used the sequence number received an error. The only + * exception to this rule is if the previous operation received one of + * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID, + * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR, + * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE. + * + */ +#define seqid_mutating_err(err) \ +(((err) != NFSERR_STALE_CLIENTID) && \ + ((err) != NFSERR_STALE_STATEID) && \ + ((err) != NFSERR_BAD_STATEID) && \ + ((err) != NFSERR_BAD_SEQID) && \ + ((err) != NFSERR_BAD_XDR) && \ + ((err) != NFSERR_RESOURCE) && \ + ((err) != NFSERR_NOFILEHANDLE)) + struct nfs4_client { - atomic_t cl_count; /* refcount */ u64 cl_clientid; /* constant */ - nfs4_verifier cl_confirm; + nfs4_verifier cl_confirm; - /* - * Starts a list of lockowners, linked through lo_list. - */ - struct list_head cl_lockowners; /* protected by state_spinlock */ + u32 cl_lockowner_id; +}; + +/* +* The ->so_sema is held during all shareowner seqid-mutating operations: +* OPEN, OPEN_DOWNGRADE, and CLOSE. +* Its purpose is to properly serialize so_seqid, as mandated by +* the protocol. +*/ +struct nfs4_shareowner { + u32 so_id; /* 32-bit identifier, unique */ + struct semaphore so_sema; + u32 so_seqid; /* protected by so_sema */ + nfs4_stateid so_stateid; /* protected by so_sema */ + unsigned int so_flags; /* protected by so_sema */ }; + /* nfs4proc.c */ extern int nfs4_proc_renew(struct nfs_server *server); /* nfs4renewd.c */ extern int nfs4_init_renewd(struct nfs_server *server); -#endif /* CONFIG_NFS_V4 */ - -#ifdef CONFIG_NFS_V4 +/* nfs4state.c */ extern struct nfs4_client *nfs4_get_client(void); extern void nfs4_put_client(struct nfs4_client *clp); +extern struct nfs4_shareowner * nfs4_get_shareowner(struct inode *inode); +void nfs4_put_shareowner(struct inode *inode, struct nfs4_shareowner *sp); +extern int nfs4_set_inode_share(struct inode * inode, + struct nfs4_shareowner *sp, unsigned int flags); +extern void nfs4_increment_seqid(u32 status, struct nfs4_shareowner *sp); +extern int nfs4_test_shareowner(struct inode *inode, unsigned int open_flags); +struct nfs4_shareowner * nfs4_get_inode_share(struct inode * inode, unsigned int open_flags); + + + + + struct nfs4_mount_data; static inline int @@ -481,6 +534,7 @@ destroy_nfsv4_state(struct nfs_server *server) #else #define create_nfsv4_state(server, data) 0 #define destroy_nfsv4_state(server) do { } while (0) +#define nfs4_put_shareowner(inode, owner) do { } while (0) #endif #endif /* __KERNEL__ */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 980705c7307e..2d1544931139 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -87,6 +87,51 @@ struct nfs_pathconf { __u32 max_namelen; /* max name length */ }; +/* + * Arguments to the open call. + */ +struct nfs_openargs { + struct nfs_fh * fh; + __u32 seqid; + __u32 share_access; + __u64 clientid; + __u32 id; + __u32 opentype; + __u32 createmode; + union { + struct iattr * attrs; /* UNCHECKED, GUARDED */ + nfs4_verifier verifier; /* EXCLUSIVE */ + } u; + struct qstr * name; + struct nfs4_getattr * f_getattr; + struct nfs4_getattr * d_getattr; +}; + +struct nfs_openres { + __u32 status; + nfs4_stateid stateid; + struct nfs_fh fh; + struct nfs4_change_info * cinfo; + __u32 rflags; + struct nfs4_getattr * f_getattr; + struct nfs4_getattr * d_getattr; +}; + +/* + * Arguments to the open_confirm call. + */ +struct nfs_open_confirmargs { + struct nfs_fh * fh; + nfs4_stateid stateid; + __u32 seqid; +}; + +struct nfs_open_confirmres { + __u32 status; + nfs4_stateid stateid; +}; + + /* * Arguments to the read call. */ -- cgit v1.2.3 From 45f3fae685e9579979b0dbed506c424688d72881 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 8 Apr 2003 04:27:37 +0200 Subject: Setup code to tear down the NFSv4 state once we're done with a file. --- fs/nfs/nfs4proc.c | 71 ++++++++++++++++++++++++++++++------------------- fs/nfs/nfs4state.c | 4 ++- fs/nfs/nfs4xdr.c | 67 ++++++++++++++++++++++++++++++++++++++-------- include/linux/nfs4.h | 1 + include/linux/nfs_fs.h | 1 + include/linux/nfs_xdr.h | 14 ++++++++++ 6 files changed, 119 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 15ce5d40f2c2..98e7cc17329e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -80,19 +80,6 @@ nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, cp->req_nops++; } -static void -nfs4_setup_close(struct nfs4_compound *cp, nfs4_stateid stateid, u32 seqid) -{ - struct nfs4_close *close = GET_OP(cp, close); - - close->cl_stateid = stateid; - close->cl_seqid = seqid; - - OPNUM(cp) = OP_CLOSE; - cp->req_nops++; - cp->renew_index = cp->req_nops; -} - static void nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name, struct iattr *sattr, struct nfs4_change_info *info) @@ -710,16 +697,44 @@ do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, return nfs4_call_compound(&compound, NULL, 0); } -static int -do_close(struct nfs_server *server, struct nfs_fh *fhandle, u32 seqid, char *stateid) +/* + * It is possible for data to be read/written from a mem-mapped file + * after the sys_close call (which hits the vfs layer as a flush). + * This means that we can't safely call nfsv4 close on a file until + * the inode is cleared. This in turn means that we are not good + * NFSv4 citizens - we do not indicate to the server to update the file's + * share state even when we are done with one of the three share + * stateid's in the inode. + */ +int +nfs4_do_close(struct inode *inode, struct nfs4_shareowner *sp) { - struct nfs4_compound compound; - struct nfs4_op ops[2]; - - nfs4_setup_compound(&compound, ops, server, "close"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_close(&compound, stateid, seqid); - return nfs4_call_compound(&compound, NULL, 0); + int status = 0; + struct nfs_closeargs arg = { + .fh = NFS_FH(inode), + }; + struct nfs_closeres res = { + .status = 0, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], + .rpc_argp = &arg, + .rpc_resp = &res, + }; + + memcpy(arg.stateid, sp->so_stateid, sizeof(nfs4_stateid)); + /* Serialization for the sequence id */ + down(&sp->so_sema); + arg.seqid = sp->so_seqid, + status = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); + + /* hmm. we are done with the inode, and in the process of freeing + * the shareowner. we keep this around to process errors + */ + nfs4_increment_seqid(status, sp); + up(&sp->so_sema); + + return status; } static int @@ -820,6 +835,12 @@ nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) return nfs4_call_compound(&compound, NULL, 0); } +/* + * The file is not closed if it is opened due to the a request to change + * the size of the file. The open call will not be needed once the + * VFS layer lookup-intents are implemented. + * Close is called when the inode is destroyed. + */ static int nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct iattr *sattr) @@ -851,15 +872,12 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, */ if (fattr->fileid != NFS_FILEID(inode)) { printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n"); - do_close(NFS_SERVER(inode), NFS_FH(inode), sp->so_seqid, sp->so_stateid); return -EIO; } } status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr, fake == 1? zero_stateid: sp->so_stateid); - if (size_change) - do_close(NFS_SERVER(inode), NFS_FH(inode), sp->so_seqid, sp->so_stateid); return status; } @@ -1059,8 +1077,7 @@ nfs4_proc_write(struct inode *inode, struct rpc_cred *cred, * conditions due to the lookup, create, and open VFS calls from sys_open() * placed on the wire. * - * Given the above sorry state of affairs, I'm simply sending an OPEN, a - * possible SETATTR, and then a CLOSE + * Given the above sorry state of affairs, I'm simply sending an OPEN. * The file will be opened again in the subsequent VFS open call * (nfs4_proc_file_open). * diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 059880274526..8243f6d7398d 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -124,7 +124,7 @@ nfs4_get_shareowner(struct inode *dir) } /* - * Called for each inode shareowner in nfs_clear_inode, + * Called for each non-null inode shareowner in nfs_clear_inode, * or if nfs4_do_open fails. */ void @@ -132,6 +132,8 @@ nfs4_put_shareowner(struct inode *inode, struct nfs4_shareowner *sp) { if (!sp) return; + if (sp->so_flags & O_ACCMODE) + nfs4_do_close(inode, sp); kfree(sp); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 319d16b0bd01..7bd0e88ebd02 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -144,6 +144,13 @@ extern int nfs_stat_to_errno(int); #define NFS4_dec_open_confirm_sz compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz + 4 +#define NFS4_enc_close_sz compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz + 5 +#define NFS4_dec_close_sz compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 4 + @@ -378,14 +385,14 @@ encode_access(struct xdr_stream *xdr, struct nfs4_access *access) } static int -encode_close(struct xdr_stream *xdr, struct nfs4_close *close) +encode_close(struct xdr_stream *xdr, struct nfs_closeargs *arg) { uint32_t *p; RESERVE_SPACE(8+sizeof(nfs4_stateid)); WRITE32(OP_CLOSE); - WRITE32(close->cl_seqid); - WRITEMEM(close->cl_stateid, sizeof(nfs4_stateid)); + WRITE32(arg->seqid); + WRITEMEM(arg->stateid, sizeof(nfs4_stateid)); return 0; } @@ -858,9 +865,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_ACCESS: status = encode_access(xdr, &cp->ops[i].u.access); break; - case OP_CLOSE: - status = encode_close(xdr, &cp->ops[i].u.close); - break; case OP_CREATE: status = encode_create(xdr, &cp->ops[i].u.create); break; @@ -940,6 +944,28 @@ nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *c cp->timestamp = jiffies; return status; } +/* + * Encode a CLOSE request + */ +static int +nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_close(&xdr, args); +out: + return status; +} + /* * Encode an OPEN request */ @@ -1229,7 +1255,7 @@ decode_access(struct xdr_stream *xdr, struct nfs4_access *access) } static int -decode_close(struct xdr_stream *xdr, struct nfs4_close *close) +decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) { uint32_t *p; int status; @@ -1238,7 +1264,7 @@ decode_close(struct xdr_stream *xdr, struct nfs4_close *close) if (status) return status; READ_BUF(sizeof(nfs4_stateid)); - COPYMEM(close->cl_stateid, sizeof(nfs4_stateid)); + COPYMEM(res->stateid, sizeof(nfs4_stateid)); return 0; } @@ -2076,9 +2102,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_ACCESS: status = decode_access(xdr, &op->u.access); break; - case OP_CLOSE: - status = decode_close(xdr, &op->u.close); - break; case OP_CREATE: status = decode_create(xdr, &op->u.create); break; @@ -2165,6 +2188,27 @@ out: return status; } +/* + * Decode CLOSE response + */ +static int +nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_close(&xdr, res); +out: + return status; +} /* * Decode OPEN response @@ -2374,6 +2418,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(COMMIT, enc_commit, dec_commit), PROC(OPEN, enc_open, dec_open), PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm), + PROC(CLOSE, enc_close, dec_close), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 02c77391d6f8..ace7f169b5dc 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -208,6 +208,7 @@ enum { NFSPROC4_CLNT_COMMIT, NFSPROC4_CLNT_OPEN, NFSPROC4_CLNT_OPEN_CONFIRM, + NFSPROC4_CLNT_CLOSE, }; #endif diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7d53fd8a8710..3d7525998534 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -491,6 +491,7 @@ struct nfs4_shareowner { /* nfs4proc.c */ extern int nfs4_proc_renew(struct nfs_server *server); +extern int nfs4_do_close(struct inode *inode, struct nfs4_shareowner *sp); /* nfs4renewd.c */ extern int nfs4_init_renewd(struct nfs_server *server); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 2d1544931139..1b1db6599e6e 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -131,6 +131,20 @@ struct nfs_open_confirmres { nfs4_stateid stateid; }; +/* + * Arguments to the close call. + */ +struct nfs_closeargs { + struct nfs_fh * fh; + nfs4_stateid stateid; + __u32 seqid; +}; + +struct nfs_closeres { + __u32 status; + nfs4_stateid stateid; +}; + /* * Arguments to the read call. -- cgit v1.2.3 From be6c1a46a0609afffd8926a2f533158a8481689c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 8 Apr 2003 04:30:19 +0200 Subject: Make NFSv4 'setattr()' method use the cached stateid if the file is already open. --- fs/nfs/nfs4proc.c | 104 +++++++++++++++++++++++++++--------------------- fs/nfs/nfs4xdr.c | 77 +++++++++++++++++++++++++++++------ include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 11 +++++ 4 files changed, 134 insertions(+), 59 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 98e7cc17329e..f302bd233380 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -461,18 +461,6 @@ nfs4_setup_savefh(struct nfs4_compound *cp) cp->req_nops++; } -static void -nfs4_setup_setattr(struct nfs4_compound *cp, char *stateid, struct iattr *iap) -{ - struct nfs4_setattr *setattr = GET_OP(cp, setattr); - - setattr->st_stateid = stateid; - setattr->st_iap = iap; - - OPNUM(cp) = OP_SETATTR; - cp->req_nops++; -} - static void nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short port) { @@ -681,20 +669,39 @@ out: return status; } -static int -do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, - struct nfs_fh *fhandle, struct iattr *sattr, char *stateid) -{ - struct nfs4_compound compound; - struct nfs4_op ops[3]; - u32 bmres[2]; - - fattr->valid = 0; - nfs4_setup_compound(&compound, ops, server, "setattr"); - nfs4_setup_putfh(&compound, fhandle); - nfs4_setup_setattr(&compound, stateid, sattr); - nfs4_setup_getattr(&compound, fattr, bmres); - return nfs4_call_compound(&compound, NULL, 0); +int +nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, + struct nfs_fh *fhandle, struct iattr *sattr, + struct nfs4_shareowner *sp) +{ + u32 g_bmres[2]; + struct nfs4_getattr getattr = { + .gt_bmval = nfs4_fattr_bitmap, + .gt_attrs = fattr, + .gt_bmres = g_bmres, + }; + struct nfs_setattrargs arg = { + .fh = fhandle, + .iap = sattr, + .attr = &getattr, + }; + struct nfs_setattrres res = { + .attr = &getattr, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], + .rpc_argp = &arg, + .rpc_resp = &res, + }; + + fattr->valid = 0; + + if (sp) + memcpy(arg.stateid, sp->so_stateid, sizeof(nfs4_stateid)); + else + memcpy(arg.stateid, zero_stateid, sizeof(nfs4_stateid)); + + return(rpc_call_sync(server->client, &msg, 0)); } /* @@ -839,7 +846,18 @@ nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) * The file is not closed if it is opened due to the a request to change * the size of the file. The open call will not be needed once the * VFS layer lookup-intents are implemented. + * * Close is called when the inode is destroyed. + * If we haven't opened the file for O_WRONLY, we + * need to in the size_change case to obtain a stateid. + * + * Got race? + * Because OPEN is always done by name in nfsv4, it is + * possible that we opened a different file by the same + * name. We can recognize this race condition, but we + * can't do anything about it besides returning an error. + * + * This will be fixed with VFS changes (lookup-intent). */ static int nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, @@ -847,37 +865,31 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, { struct inode * inode = dentry->d_inode; int size_change = sattr->ia_valid & ATTR_SIZE; - struct nfs_fh throwaway_fh; struct nfs4_shareowner *sp = NULL; - int status, fake = 1; + int status; fattr->valid = 0; if (size_change) { + if (NFS_I(inode)->wo_owner) { + /* file is already open for O_WRONLY */ + sp = NFS_I(inode)->wo_owner; + goto no_open; + } status = nfs4_do_open(dentry->d_parent->d_inode, - &dentry->d_name, - O_WRONLY, NULL, fattr, - &throwaway_fh,&sp); + &dentry->d_name, O_WRONLY, NULL, fattr, + NULL, &sp); if (status) return status; - fake = 0; - /* - * Because OPEN is always done by name in nfsv4, it is - * possible that we opened a different file by the same - * name. We can recognize this race condition, but we - * can't do anything about it besides returning an error. - * - * XXX: Should we compare filehandles too, as in - * nfs_find_actor()? - */ + if (fattr->fileid != NFS_FILEID(inode)) { printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n"); return -EIO; } } - - status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr, - fake == 1? zero_stateid: sp->so_stateid); +no_open: + status = nfs4_do_setattr(NFS_SERVER(inode), fattr, + NFS_FH(inode), sattr, sp); return status; } @@ -1097,8 +1109,8 @@ nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, status = nfs4_do_open(dir, name, oflags, sattr, fattr, fhandle, &sp); if (!status) { if (flags & O_EXCL) { - status = do_setattr(NFS_SERVER(dir), fattr, - fhandle, sattr, sp->so_stateid); + status = nfs4_do_setattr(NFS_SERVER(dir), fattr, + fhandle, sattr, sp); /* XXX should i bother closing the file? */ } } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7bd0e88ebd02..ef6e32ce91be 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -150,8 +150,14 @@ extern int nfs_stat_to_errno(int); #define NFS4_dec_close_sz compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz + 4 - - +#define NFS4_enc_setattr_sz compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + op_encode_hdr_maxsz + 4 + \ + nfs4_fattr_bitmap_maxsz + \ + encode_getattr_maxsz +#define NFS4_dec_setattr_sz compound_decode_hdr_maxsz + \ + decode_putfh_maxsz + \ + op_decode_hdr_maxsz + 3 static struct { @@ -771,16 +777,16 @@ encode_savefh(struct xdr_stream *xdr) } static int -encode_setattr(struct xdr_stream *xdr, struct nfs4_setattr *setattr) +encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg) { int status; uint32_t *p; RESERVE_SPACE(4+sizeof(nfs4_stateid)); WRITE32(OP_SETATTR); - WRITEMEM(setattr->st_stateid, sizeof(nfs4_stateid)); + WRITEMEM(arg->stateid, sizeof(nfs4_stateid)); - if ((status = encode_attrs(xdr, setattr->st_iap))) + if ((status = encode_attrs(xdr, arg->iap))) return status; return 0; @@ -907,9 +913,6 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_SAVEFH: status = encode_savefh(xdr); break; - case OP_SETATTR: - status = encode_setattr(xdr, &cp->ops[i].u.setattr); - break; case OP_SETCLIENTID: status = encode_setclientid(xdr, &cp->ops[i].u.setclientid); break; @@ -1061,6 +1064,31 @@ out: return status; } +/* + * Encode an SETATTR request + */ +static int +nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 3, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + status = encode_putfh(&xdr, args->fh); + if(status) + goto out; + status = encode_setattr(&xdr, args); + if(status) + goto out; + status = encode_getattr(&xdr, args->attr); +out: + return status; +} + /* * Encode a WRITE request */ @@ -1991,7 +2019,7 @@ decode_savefh(struct xdr_stream *xdr) } static int -decode_setattr(struct xdr_stream *xdr) +decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) { uint32_t *p; uint32_t bmlen; @@ -2144,9 +2172,6 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs case OP_SAVEFH: status = decode_savefh(xdr); break; - case OP_SETATTR: - status = decode_setattr(xdr); - break; case OP_SETCLIENTID: status = decode_setclientid(xdr, &op->u.setclientid); break; @@ -2274,6 +2299,31 @@ out: return status; } +/* + * Decode SETATTR response + */ +static int +nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status) + goto out; + status = decode_putfh(&xdr); + if (status) + goto out; + status = decode_setattr(&xdr, res); + if (status) + goto out; + status = decode_getattr(&xdr, res->attr); +out: + return status; +} + /* * Decode Read response @@ -2418,7 +2468,8 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(COMMIT, enc_commit, dec_commit), PROC(OPEN, enc_open, dec_open), PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm), - PROC(CLOSE, enc_close, dec_close), + PROC(CLOSE, enc_close, dec_close), + PROC(SETATTR, enc_setattr, dec_setattr), }; struct rpc_version nfs_version4 = { diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index ace7f169b5dc..de82796383bf 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -209,6 +209,7 @@ enum { NFSPROC4_CLNT_OPEN, NFSPROC4_CLNT_OPEN_CONFIRM, NFSPROC4_CLNT_CLOSE, + NFSPROC4_CLNT_SETATTR, }; #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 1b1db6599e6e..7c37e245e732 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -241,6 +241,17 @@ struct nfs_renameargs { unsigned int tolen; }; +struct nfs_setattrargs { + struct nfs_fh * fh; + nfs4_stateid stateid; + struct iattr * iap; + struct nfs4_getattr * attr; +}; + +struct nfs_setattrres { + struct nfs4_getattr * attr; +}; + struct nfs_linkargs { struct nfs_fh * fromfh; struct nfs_fh * tofh; -- cgit v1.2.3 From 47462c3c70719e77c7431dfd8ac0a722bc026087 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 8 Apr 2003 04:31:06 +0200 Subject: Make NFSv4 'read' code use the cached stateid if it exists. --- fs/nfs/nfs4proc.c | 26 ++++++++++++++++++++++++++ fs/nfs/nfs4xdr.c | 5 +---- include/linux/nfs_xdr.h | 1 + 3 files changed, 28 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f302bd233380..966cdddf2940 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1013,6 +1013,7 @@ nfs4_proc_read(struct inode *inode, struct rpc_cred *cred, struct page *page, int *eofp) { struct nfs_server *server = NFS_SERVER(inode); + struct nfs4_shareowner *sp; uint64_t offset = page_offset(page) + base; struct nfs_readargs arg = { .fh = NFS_FH(inode), @@ -1035,6 +1036,17 @@ nfs4_proc_read(struct inode *inode, struct rpc_cred *cred, int status; dprintk("NFS call read %d @ %Ld\n", count, (long long)offset); + /* + * Try first to use O_RDONLY, then O_RDWR stateid. + */ + sp = nfs4_get_inode_share(inode, O_RDONLY); + if (!sp) + sp = nfs4_get_inode_share(inode, O_RDWR); + if (sp) + memcpy(arg.stateid,sp->so_stateid, sizeof(nfs4_stateid)); + else + memcpy(arg.stateid, zero_stateid, sizeof(nfs4_stateid)); + fattr->valid = 0; status = rpc_call_sync(server->client, &msg, flags); if (!status) { @@ -1441,6 +1453,7 @@ nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count) }; struct inode *inode = data->inode; struct nfs_page *req = nfs_list_entry(data->pages.next); + struct nfs4_shareowner *sp; int flags; data->args.fh = NFS_FH(inode); @@ -1453,6 +1466,19 @@ nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count) data->res.eof = 0; data->timestamp = jiffies; + if(req->wb_file) { + unsigned int oflags = req->wb_file->f_flags; + sp = nfs4_get_inode_share(inode, oflags); + } else { + sp = nfs4_get_inode_share(inode, O_RDONLY); + if (!sp) + sp = nfs4_get_inode_share(inode, O_RDWR); + } + if (sp) + memcpy(data->args.stateid,sp->so_stateid, sizeof(nfs4_stateid)); + else + memcpy(data->args.stateid, zero_stateid, sizeof(nfs4_stateid)); + /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ef6e32ce91be..78eca301cf93 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -654,10 +654,7 @@ encode_read(struct xdr_stream *xdr, struct nfs_readargs *args) RESERVE_SPACE(32); WRITE32(OP_READ); - WRITE32(0); /* all-zero stateid! */ - WRITE32(0); - WRITE32(0); - WRITE32(0); + WRITEMEM(args->stateid, sizeof(nfs4_stateid)); WRITE64(args->offset); WRITE32(args->count); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 7c37e245e732..515168676c24 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -157,6 +157,7 @@ struct nfs_closeres { struct nfs_readargs { struct nfs_fh * fh; + nfs4_stateid stateid; __u64 offset; __u32 count; unsigned int pgbase; -- cgit v1.2.3 From ec0e388d853a42585595652150fa27b449609a45 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 8 Apr 2003 04:31:46 +0200 Subject: Make the NFSv4 write code use the stateid if it exists. --- fs/nfs/nfs4proc.c | 32 +++++++++++++++++++++++++++++++- fs/nfs/nfs4xdr.c | 5 +---- include/linux/nfs_xdr.h | 1 + 3 files changed, 33 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 966cdddf2940..fac24a46af0b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -55,7 +55,8 @@ extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; static nfs4_stateid zero_stateid = - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + static spinlock_t renew_lock = SPIN_LOCK_UNLOCKED; static void @@ -1067,6 +1068,7 @@ nfs4_proc_write(struct inode *inode, struct rpc_cred *cred, struct page *page, struct nfs_writeverf *verf) { struct nfs_server *server = NFS_SERVER(inode); + struct nfs4_shareowner *sp; uint64_t offset = page_offset(page) + base; struct nfs_writeargs arg = { .fh = NFS_FH(inode), @@ -1090,6 +1092,19 @@ nfs4_proc_write(struct inode *inode, struct rpc_cred *cred, int rpcflags = (flags & NFS_RW_SWAP) ? NFS_RPC_SWAPFLAGS : 0; dprintk("NFS call write %d @ %Ld\n", count, (long long)offset); + + /* + * Try first to use O_WRONLY, then O_RDWR stateid. + */ + sp = nfs4_get_inode_share(inode, O_WRONLY); + if (!sp) + sp = nfs4_get_inode_share(inode, O_RDWR); + + if (sp) + memcpy(arg.stateid,sp->so_stateid, sizeof(nfs4_stateid)); + else + memcpy(arg.stateid, zero_stateid, sizeof(nfs4_stateid)); + fattr->valid = 0; return rpc_call_sync(server->client, &msg, rpcflags); } @@ -1531,6 +1546,7 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) }; struct inode *inode = data->inode; struct nfs_page *req = nfs_list_entry(data->pages.next); + struct nfs4_shareowner *sp; int stable; int flags; @@ -1553,6 +1569,20 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how) data->res.verf = &data->verf; data->timestamp = jiffies; + if(req->wb_file) { + unsigned int oflags = req->wb_file->f_flags; + sp = nfs4_get_inode_share(inode, oflags); + } else { + sp = nfs4_get_inode_share(inode, O_WRONLY); + if (!sp) + sp = nfs4_get_inode_share(inode, O_RDWR); + } + + if (sp) + memcpy(data->args.stateid,sp->so_stateid, sizeof(nfs4_stateid)); + else + memcpy(data->args.stateid, zero_stateid, sizeof(nfs4_stateid)); + /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 78eca301cf93..5956f7e24953 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -837,10 +837,7 @@ encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args) RESERVE_SPACE(36); WRITE32(OP_WRITE); - WRITE32(0xffffffff); /* magic stateid -1 */ - WRITE32(0xffffffff); - WRITE32(0xffffffff); - WRITE32(0xffffffff); + WRITEMEM(args->stateid, sizeof(nfs4_stateid)); WRITE64(args->offset); WRITE32(args->stable); WRITE32(args->count); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 515168676c24..14314f089e8d 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -180,6 +180,7 @@ struct nfs_readres { struct nfs_writeargs { struct nfs_fh * fh; + nfs4_stateid stateid; __u64 offset; __u32 count; enum nfs3_stable_how stable; -- cgit v1.2.3 From 8e8c637b6ce567e5ccedf64d9cdb89dcfd57b34d Mon Sep 17 00:00:00 2001 From: Marius Aamodt Eriksen Date: Tue, 8 Apr 2003 04:46:27 +0200 Subject: Add support for mapping NFSv4 remote user/group names into local unix-style uid/gids. Note that this makes use of the RPC client upcall mechanism (rpc_pipefs) to notify a userland daemon that does the actual mapping. The results are then cached in the kernel. The userland daemon can be downloaded from the CITI NFSv4 page at http://www.citi.umich.edu/projects/nfsv4/ --- fs/nfs/Makefile | 3 +- fs/nfs/idmap.c | 474 ++++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/inode.c | 12 ++ include/linux/nfs_fs_sb.h | 1 + include/linux/nfs_idmap.h | 69 +++++++ 5 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 fs/nfs/idmap.c create mode 100644 include/linux/nfs_idmap.h (limited to 'include/linux') diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index b461485f00df..d85ccd52a345 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \ proc.o read.o symlink.o unlink.o write.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o -nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o +nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ + idmap.o nfs-$(CONFIG_NFS_DIRECTIO) += direct.o nfs-objs := $(nfs-y) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c new file mode 100644 index 000000000000..d755dcad994d --- /dev/null +++ b/fs/nfs/idmap.c @@ -0,0 +1,474 @@ +/* + * fs/nfs/idmap.c + * + * UID and GID to name mapping for clients. + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. + * + * Marius Aamodt Eriksen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define IDMAP_HASH_SZ 128 +#define IDMAP_HASH_TYPE_NAME 0x01 +#define IDMAP_HASH_TYPE_ID 0x02 +#define IDMAP_HASH_TYPE_INSERT 0x04 + +struct idmap_hashent { + uid_t ih_id; + char ih_name[IDMAP_NAMESZ]; + u_int32_t ih_namelen; +}; + +struct idmap { + char idmap_path[48]; + struct dentry *idmap_dentry; + wait_queue_head_t idmap_wq; + struct idmap_msg idmap_im; + struct nfs_server *idmap_server; + struct semaphore idmap_lock; + struct semaphore idmap_im_lock; + struct semaphore idmap_hash_lock; + struct idmap_hashent idmap_id_hash[IDMAP_HASH_SZ]; + struct idmap_hashent idmap_name_hash[IDMAP_HASH_SZ]; +}; + +static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *, char *, + size_t); +static ssize_t idmap_pipe_downcall(struct file *, const char *, size_t); +void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); + +static int validate_ascii(char *, u_int32_t); + +static u_int32_t fnvhash32(void *, u_int32_t); +static int idmap_cache_lookup(struct idmap *, int, char *, u_int32_t *, uid_t *); + +static struct rpc_pipe_ops idmap_upcall_ops = { + .upcall = idmap_pipe_upcall, + .downcall = idmap_pipe_downcall, + .destroy_msg = idmap_pipe_destroy_msg, +}; + +void * +nfs_idmap_new(struct nfs_server *server) +{ + struct idmap *idmap; + + if ((idmap = kmalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) + return (NULL); + + memset(idmap, 0, sizeof(*idmap)); + + idmap->idmap_server = server; + + snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), + "%s/idmap", idmap->idmap_server->client->cl_pathname); + + idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path, + idmap->idmap_server, &idmap_upcall_ops); + if (IS_ERR(idmap->idmap_dentry)) + goto err_free; + + init_MUTEX(&idmap->idmap_lock); + init_MUTEX(&idmap->idmap_im_lock); + init_MUTEX(&idmap->idmap_hash_lock); + + return (idmap); + + err_free: + kfree(idmap); + return (NULL); +} + +void +nfs_idmap_delete(struct nfs_server *server) +{ + struct idmap *idmap = server->idmap; + + rpc_unlink(idmap->idmap_path); + kfree(idmap); +} + +/* + * Name -> ID + */ +int +nfs_idmap_id(struct nfs_server *server, u_int8_t type, char *name, + u_int namelen, uid_t *id) +{ + struct rpc_pipe_msg msg; + struct idmap *idmap = server->idmap; + struct idmap_msg *im; + DECLARE_WAITQUEUE(wq, current); + int ret = -1, hashtype = IDMAP_HASH_TYPE_NAME, xnamelen = namelen; + + if (idmap == NULL) + return (-1); + + im = &idmap->idmap_im; + + if (namelen > IDMAP_NAMESZ || namelen == 0) + return (-1); + + down(&idmap->idmap_lock); + down(&idmap->idmap_im_lock); + + if (name[xnamelen - 1] == '\0') + xnamelen--; + + if (idmap_cache_lookup(idmap, hashtype, name, &xnamelen, id) == 0) { + ret = 0; + goto out; + } + + memset(im, 0, sizeof(*im)); + memcpy(im->im_name, name, namelen); + /* Make sure the string is NULL terminated */ + if (namelen != xnamelen) { + /* We cannot fit a NULL character */ + if (namelen == IDMAP_NAMESZ) { + ret = -1; + goto out; + } + im->im_name[namelen] = '\0'; + } + + im->im_type = type; + im->im_conv = IDMAP_CONV_NAMETOID; + + memset(&msg, 0, sizeof(msg)); + msg.data = im; + msg.len = sizeof(*im); + + init_waitqueue_head(&idmap->idmap_wq); + add_wait_queue(&idmap->idmap_wq, &wq); + set_current_state(TASK_UNINTERRUPTIBLE); + + if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { + set_current_state(TASK_RUNNING); + goto out; + } + + up(&idmap->idmap_im_lock); + schedule(); + down(&idmap->idmap_im_lock); + + /* + * XXX Race condition here, with testing for status. Go ahead + * and and do the cace lookup anyway. + */ + if (im->im_status & IDMAP_STATUS_SUCCESS) { + ret = 0; + *id = im->im_id; + + hashtype |= IDMAP_HASH_TYPE_INSERT; + ret = idmap_cache_lookup(idmap, hashtype, name, &xnamelen, id); + } + + out: + memset(im, 0, sizeof(*im)); + up(&idmap->idmap_im_lock); + up(&idmap->idmap_lock); + return (ret); +} + +/* + * ID -> Name + */ +int +nfs_idmap_name(struct nfs_server *server, u_int8_t type, uid_t id, + char *name, u_int *namelen) +{ + struct rpc_pipe_msg msg; + struct idmap *idmap = server->idmap; + struct idmap_msg *im; + DECLARE_WAITQUEUE(wq, current); + int ret = -1, hashtype = IDMAP_HASH_TYPE_ID; + u_int len; + + if (idmap == NULL) + return (-1); + + im = &idmap->idmap_im; + + if (*namelen < IDMAP_NAMESZ || *namelen == 0) + return (-1); + + down(&idmap->idmap_lock); + down(&idmap->idmap_im_lock); + + if (idmap_cache_lookup(idmap, hashtype, name, namelen, &id) == 0) { + ret = 0; + goto out; + } + + memset(im, 0, sizeof(*im)); + im->im_type = type; + im->im_conv = IDMAP_CONV_IDTONAME; + im->im_id = id; + + memset(&msg, 0, sizeof(msg)); + msg.data = im; + msg.len = sizeof(*im); + + init_waitqueue_head(&idmap->idmap_wq); + add_wait_queue(&idmap->idmap_wq, &wq); + set_current_state(TASK_UNINTERRUPTIBLE); + + if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { + set_current_state(TASK_RUNNING); + goto out; + } + + /* + * XXX add timeouts here + */ + up(&idmap->idmap_im_lock); + schedule(); + down(&idmap->idmap_im_lock); + + if (im->im_status & IDMAP_STATUS_SUCCESS) { + if ((len = validate_ascii(im->im_name, IDMAP_NAMESZ)) == -1) + goto out; + ret = 0; + memcpy(name, im->im_name, len); + *namelen = len; + + hashtype |= IDMAP_HASH_TYPE_INSERT; + ret = idmap_cache_lookup(idmap, hashtype, name, namelen, &id); + } + + out: + memset(im, 0, sizeof(*im)); + up(&idmap->idmap_im_lock); + up(&idmap->idmap_lock); + return (ret); +} + +static ssize_t +idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, + char *dst, size_t buflen) +{ + char *data = (char *)msg->data + msg->copied; + ssize_t mlen = msg->len - msg->copied; + ssize_t left; + + if (mlen > buflen) + mlen = buflen; + + left = copy_to_user(dst, data, mlen); + + return (mlen - left); +} + +static ssize_t +idmap_pipe_downcall(struct file *filp, const char *src, size_t mlen) +{ + struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode); + struct nfs_server *server = rpci->private; + struct idmap *idmap = server->idmap; + struct idmap_msg im_in, *im = &idmap->idmap_im; + int match = 0, hashtype, badmsg = 0, namelen_in, namelen; + + if (mlen != sizeof(im_in)) + return (-ENOSPC); + + if (copy_from_user(&im_in, src, mlen) != 0) + return (-EFAULT); + + down(&idmap->idmap_im_lock); + + namelen_in = validate_ascii(im_in.im_name, IDMAP_NAMESZ); + namelen = validate_ascii(im->im_name, IDMAP_NAMESZ); + + badmsg = !(im_in.im_status & IDMAP_STATUS_SUCCESS) || namelen_in <= 0; + + switch (im_in.im_conv) { + case IDMAP_CONV_IDTONAME: + match = im->im_id == im_in.im_id; + break; + case IDMAP_CONV_NAMETOID: + match = namelen == namelen_in && + memcmp(im->im_name, im_in.im_name, namelen) == 0; + break; + default: + badmsg = 1; + break; + } + + match = match && im->im_type == im_in.im_type; + + if (match) { + memcpy(im, &im_in, sizeof(*im)); + wake_up(&idmap->idmap_wq); + __rpc_purge_current_upcall(filp); + } else if (!badmsg) { + hashtype = im_in.im_conv == IDMAP_CONV_IDTONAME ? + IDMAP_HASH_TYPE_ID : IDMAP_HASH_TYPE_NAME; + hashtype |= IDMAP_HASH_TYPE_INSERT; + idmap_cache_lookup(idmap, hashtype, im_in.im_name, &namelen_in, + &im_in.im_id); + } + + up(&idmap->idmap_im_lock); + return (mlen); +} + +void +idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) +{ + struct idmap_msg *im = msg->data; + struct idmap *idmap = container_of(im, struct idmap, idmap_im); + + down(&idmap->idmap_im_lock); + im->im_status = IDMAP_STATUS_LOOKUPFAIL; + wake_up(&idmap->idmap_wq); + up(&idmap->idmap_im_lock); +} + +static int +validate_ascii(char *string, u_int32_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (string[i] == '\0') + break; + + if (string[i] & 0x80) + return (-1); + } + + if (string[i] != '\0') + return (-1); + + return (i); +} + +/* + * Fowler/Noll/Vo hash + * http://www.isthe.com/chongo/tech/comp/fnv/ + */ + +#define FNV_P_32 ((u_int32_t)0x01000193) /* 16777619 */ +#define FNV_1_32 ((u_int32_t)0x811c9dc5) /* 2166136261 */ + +static u_int32_t +fnvhash32(void *buf, u_int32_t buflen) +{ + u_char *p, *end = (u_char *)buf + buflen; + u_int32_t hash = FNV_1_32; + + for (p = buf; p < end; p++) { + hash *= FNV_P_32; + hash ^= (u_int32_t)*p; + } + + return (hash); +} + +/* + * ->ih_namelen == 0 indicates negative entry + */ +static int +idmap_cache_lookup(struct idmap *idmap, int type, char *name, u_int32_t *namelen, + uid_t *id) +{ + u_int32_t hash; + struct idmap_hashent *he = NULL; + int insert = type & IDMAP_HASH_TYPE_INSERT; + int ret = -1; + + /* + * XXX technically, this is not needed, since we will always + * hold idmap_im_lock when altering the hash tables. but + * semantically that just hurts. + * + * XXX cache negative responses + */ + down(&idmap->idmap_hash_lock); + + if (*namelen > IDMAP_NAMESZ || *namelen == 0) + goto out; + + if (type & IDMAP_HASH_TYPE_NAME) { + hash = fnvhash32(name, *namelen) % IDMAP_HASH_SZ; + he = &idmap->idmap_name_hash[hash]; + + /* + * Testing he->ih_namelen == *namelen implicitly tests + * namelen != 0, and thus a non-negative entry. + */ + if (!insert && he->ih_namelen == *namelen && + memcmp(he->ih_name, name, *namelen) == 0) { + *id = he->ih_id; + ret = 0; + goto out; + } + } + + if (type & IDMAP_HASH_TYPE_ID) { + hash = fnvhash32(id, sizeof(*id)) % IDMAP_HASH_SZ; + he = &idmap->idmap_id_hash[hash]; + + if (!insert && *id == he->ih_id && he->ih_namelen != 0 && + *namelen >= he->ih_namelen) { + memcpy(name, he->ih_name, he->ih_namelen); + *namelen = he->ih_namelen; + ret = 0; + goto out; + } + } + + if (insert && he != NULL) { + he->ih_id = *id; + memcpy(he->ih_name, name, *namelen); + he->ih_namelen = *namelen; + ret = 0; + } + + out: + up(&idmap->idmap_hash_lock); + return (ret); +} diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2e8d2e1daeec..712717913231 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -152,6 +153,11 @@ nfs_put_super(struct super_block *sb) struct nfs_server *server = NFS_SB(sb); struct rpc_clnt *rpc; +#ifdef CONFIG_NFS_V4 + if (server->idmap != NULL) + nfs_idmap_delete(server); +#endif /* CONFIG_NFS_V4 */ + if ((rpc = server->client) != NULL) rpc_shutdown_client(rpc); @@ -160,6 +166,7 @@ nfs_put_super(struct super_block *sb) rpciod_down(); /* release rpciod */ destroy_nfsv4_state(server); + kfree(server->hostname); } @@ -1362,11 +1369,16 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, if (create_nfsv4_state(server, data)) goto out_shutdown; + if ((server->idmap = nfs_idmap_new(server)) == NULL) + printk(KERN_WARNING "NFS: couldn't start IDmap\n"); + err = nfs_sb_init(sb); if (err == 0) return 0; rpciod_down(); destroy_nfsv4_state(server); + if (server->idmap != NULL) + nfs_idmap_delete(server); out_shutdown: rpc_shutdown_client(server->client); out_fail: diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index cee23453bddc..816d447df238 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -36,6 +36,7 @@ struct nfs_server { struct nfs4_client * nfs4_state; /* all NFSv4 state starts here */ unsigned long lease_time; /* in jiffies */ unsigned long last_renewal; /* in jiffies */ + void *idmap; #endif }; diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h new file mode 100644 index 000000000000..248adf707071 --- /dev/null +++ b/include/linux/nfs_idmap.h @@ -0,0 +1,69 @@ +/* + * include/linux/nfs_idmap.h + * + * UID and GID to name mapping for clients. + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. + * + * Marius Aamodt Eriksen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NFS_IDMAP_H +#define NFS_IDMAP_H + +/* XXX from bits/utmp.h */ +#define IDMAP_NAMESZ 128 + +#define IDMAP_TYPE_USER 0 +#define IDMAP_TYPE_GROUP 1 + +#define IDMAP_CONV_IDTONAME 0 +#define IDMAP_CONV_NAMETOID 1 + +#define IDMAP_STATUS_INVALIDMSG 0x01 +#define IDMAP_STATUS_AGAIN 0x02 +#define IDMAP_STATUS_LOOKUPFAIL 0x04 +#define IDMAP_STATUS_SUCCESS 0x08 + +struct idmap_msg { + u_int8_t im_type; + u_int8_t im_conv; + char im_name[IDMAP_NAMESZ]; + u_int32_t im_id; + u_int8_t im_status; +}; + +#ifdef __KERNEL__ +void *nfs_idmap_new(struct nfs_server *); +void nfs_idmap_delete(struct nfs_server *); +int nfs_idmap_id(struct nfs_server *, u_int8_t, char *, u_int, uid_t *); +int nfs_idmap_name(struct nfs_server *, u_int8_t, uid_t, char *, u_int *); +#endif /* __KERNEL__ */ + +#endif /* NFS_IDMAP_H */ -- cgit v1.2.3 From c52301120c3f846bc0966e880a9f0a5aee78d39a Mon Sep 17 00:00:00 2001 From: Marius Aamodt Eriksen Date: Tue, 8 Apr 2003 04:47:26 +0200 Subject: Add hooks into the NFSv4 XDR code to make use of the new uid/gid mapper upcall mechanism. --- fs/nfs/nfs4proc.c | 4 ++ fs/nfs/nfs4xdr.c | 151 ++++++++++++++++++++---------------------------- include/linux/nfs_xdr.h | 4 ++ 3 files changed, 70 insertions(+), 89 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index fac24a46af0b..a56808d6b847 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -596,11 +596,13 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, .name = name, .f_getattr = &f_getattr, .d_getattr = &d_getattr, + .server = server, }; struct nfs_openres o_res = { .cinfo = &d_cinfo, .f_getattr = &f_getattr, .d_getattr = &d_getattr, + .server = server, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], @@ -685,9 +687,11 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, .fh = fhandle, .iap = sattr, .attr = &getattr, + .server = server, }; struct nfs_setattrres res = { .attr = &getattr, + .server = server, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5956f7e24953..91d90ee6f581 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -8,7 +8,7 @@ * * Kendrick Smith * Andy Adamson - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -50,6 +50,7 @@ #include #include #include +#include #define NFSDBG_FACILITY NFSDBG_XDR @@ -233,30 +234,9 @@ encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) return 0; } -/* - * FIXME: The following dummy entries will be replaced once the userland - * upcall gets in... - */ -static int -encode_uid(char *p, uid_t uid) -{ - strcpy(p, "nobody"); - return 6; -} - -/* - * FIXME: The following dummy entries will be replaced once the userland - * upcall gets in... - */ -static int -encode_gid(char *p, gid_t gid) -{ - strcpy(p, "nobody"); - return 6; -} - static int -encode_attrs(struct xdr_stream *xdr, struct iattr *iap) +encode_attrs(struct xdr_stream *xdr, struct iattr *iap, + struct nfs_server *server) { char owner_name[256]; char owner_group[256]; @@ -284,20 +264,27 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap) if (iap->ia_valid & ATTR_MODE) len += 4; if (iap->ia_valid & ATTR_UID) { - status = owner_namelen = encode_uid(owner_name, iap->ia_uid); + status = nfs_idmap_name(server, IDMAP_TYPE_USER, + iap->ia_uid, owner_name, &owner_namelen); if (status < 0) { printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", iap->ia_uid); - goto out; + /* XXX */ + strcpy(owner_name, "nobody"); + owner_namelen = sizeof("nobody") - 1; + /* goto out; */ } len += 4 + (XDR_QUADLEN(owner_namelen) << 2); } if (iap->ia_valid & ATTR_GID) { - status = owner_grouplen = encode_gid(owner_group, iap->ia_gid); + status = nfs_idmap_name(server, IDMAP_TYPE_GROUP, + iap->ia_gid, owner_group, &owner_grouplen); if (status < 0) { printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", iap->ia_gid); - goto out; + strcpy(owner_group, "nobody"); + owner_grouplen = sizeof("nobody") - 1; + /* goto out; */ } len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); } @@ -417,7 +404,8 @@ encode_commit(struct xdr_stream *xdr, struct nfs_writeargs *args) } static int -encode_create(struct xdr_stream *xdr, struct nfs4_create *create) +encode_create(struct xdr_stream *xdr, struct nfs4_create *create, + struct nfs_server *server) { uint32_t *p; @@ -446,7 +434,7 @@ encode_create(struct xdr_stream *xdr, struct nfs4_create *create) WRITE32(create->cr_namelen); WRITEMEM(create->cr_name, create->cr_namelen); - return encode_attrs(xdr, create->cr_attrs); + return encode_attrs(xdr, create->cr_attrs, server); } static int @@ -589,7 +577,7 @@ encode_open(struct xdr_stream *xdr, struct nfs_openargs *arg) else if (arg->u.attrs) { RESERVE_SPACE(4); WRITE32(arg->createmode); - if ((status = encode_attrs(xdr, arg->u.attrs))) + if ((status = encode_attrs(xdr, arg->u.attrs, arg->server))) return status; } else { @@ -774,7 +762,8 @@ encode_savefh(struct xdr_stream *xdr) } static int -encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg) +encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg, + struct nfs_server *server) { int status; uint32_t *p; @@ -783,7 +772,7 @@ encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg) WRITE32(OP_SETATTR); WRITEMEM(arg->stateid, sizeof(nfs4_stateid)); - if ((status = encode_attrs(xdr, arg->iap))) + if ((status = encode_attrs(xdr, arg->iap, server))) return status; return 0; @@ -866,7 +855,7 @@ encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs status = encode_access(xdr, &cp->ops[i].u.access); break; case OP_CREATE: - status = encode_create(xdr, &cp->ops[i].u.create); + status = encode_create(xdr, &cp->ops[i].u.create, cp->server); break; case OP_GETATTR: status = encode_getattr(xdr, &cp->ops[i].u.getattr); @@ -983,7 +972,7 @@ nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args) status = encode_savefh(&xdr); if (status) goto out; - status = encode_open(&xdr,args); + status = encode_open(&xdr, args); if (status) goto out; status = encode_getattr(&xdr, args->f_getattr); @@ -1063,6 +1052,7 @@ out: */ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args) + { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1075,7 +1065,7 @@ nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs * status = encode_putfh(&xdr, args->fh); if(status) goto out; - status = encode_setattr(&xdr, args); + status = encode_setattr(&xdr, args, args->server); if(status) goto out; status = encode_getattr(&xdr, args->attr); @@ -1182,28 +1172,6 @@ xdr_error: \ } \ } while (0) -/* - * FIXME: The following dummy entry will be replaced once the userland - * upcall gets in... - */ -static int -decode_uid(char *p, uint32_t len, uid_t *uid) -{ - *uid = -2; - return 0; -} - -/* - * FIXME: The following dummy entry will be replaced once the userland - * upcall gets in... - */ -static int -decode_gid(char *p, uint32_t len, gid_t *gid) -{ - *gid = -2; - return 0; -} - static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { @@ -1328,7 +1296,8 @@ extern uint32_t nfs4_fsstat_bitmap[2]; extern uint32_t nfs4_pathconf_bitmap[2]; static int -decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr) +decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, + struct nfs_server *server) { struct nfs_fattr *nfp = getattr->gt_attrs; struct nfs_fsstat *fsstat = getattr->gt_fsstat; @@ -1492,35 +1461,39 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr) } if (bmval1 & FATTR4_WORD1_OWNER) { READ_BUF(4); - len += 4; - READ32(dummy32); /* name length */ - if (dummy32 > XDR_MAX_NETOBJ) { + len += 4; + READ32(dummy32); /* name length */ + if (dummy32 > XDR_MAX_NETOBJ) { dprintk("read_attrs: name too long!\n"); - goto xdr_error; - } - READ_BUF(dummy32); - len += (XDR_QUADLEN(dummy32) << 2); - if ((status = decode_uid((char *)p, dummy32, &nfp->uid))) { - dprintk("read_attrs: gss_get_num failed!\n"); - goto out; - } - dprintk("read_attrs: uid=%d\n", (int)nfp->uid); + goto xdr_error; + } + READ_BUF(dummy32); + len += (XDR_QUADLEN(dummy32) << 2); + if ((status = nfs_idmap_id(server, IDMAP_TYPE_USER, + (char *)p, len, &nfp->uid)) == -1) { + dprintk("read_attrs: gss_get_num failed!\n"); + /* goto out; */ + nfp->uid = -2; + } + dprintk("read_attrs: uid=%d\n", (int)nfp->uid); } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { READ_BUF(4); - len += 4; - READ32(dummy32); - if (dummy32 > XDR_MAX_NETOBJ) { - dprintk("read_attrs: name too long!\n"); - goto xdr_error; - } - READ_BUF(dummy32); - len += (XDR_QUADLEN(dummy32) << 2); - if ((status = decode_gid((char *)p, dummy32, &nfp->gid))) { - dprintk("read_attrs: gss_get_num failed!\n"); - goto out; - } - dprintk("read_attrs: gid=%d\n", (int)nfp->gid); + len += 4; + READ32(dummy32); + if (dummy32 > XDR_MAX_NETOBJ) { + dprintk("read_attrs: name too long!\n"); + goto xdr_error; + } + READ_BUF(dummy32); + len += (XDR_QUADLEN(dummy32) << 2); + if ((status = nfs_idmap_id(server, IDMAP_TYPE_GROUP, + (char *)p, len, &nfp->gid)) == -1) { + dprintk("read_attrs: gss_get_num failed!\n"); + nfp->gid = -2; + /* goto out; */ + } + dprintk("read_attrs: gid=%d\n", (int)nfp->gid); } if (bmval1 & FATTR4_WORD1_RAWDEV) { uint32_t major, minor; @@ -2128,7 +2101,7 @@ decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqs status = decode_create(xdr, &op->u.create); break; case OP_GETATTR: - status = decode_getattr(xdr, &op->u.getattr); + status = decode_getattr(xdr, &op->u.getattr, cp->server); break; case OP_GETFH: status = decode_getfh(xdr, &op->u.getfh); @@ -2255,7 +2228,7 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) status = decode_open(&xdr, res); if (status) goto out; - status = decode_getattr(&xdr, res->f_getattr); + status = decode_getattr(&xdr, res->f_getattr, res->server); if (status) goto out; status = decode_getfh(&xdr, &gfh); @@ -2264,7 +2237,7 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res) status = decode_restorefh(&xdr); if (status) goto out; - status = decode_getattr(&xdr, res->d_getattr); + status = decode_getattr(&xdr, res->d_getattr, res->server); if (status) goto out; out: @@ -2313,7 +2286,7 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres status = decode_setattr(&xdr, res); if (status) goto out; - status = decode_getattr(&xdr, res->attr); + status = decode_getattr(&xdr, res->attr, res->server); out: return status; } @@ -2448,7 +2421,7 @@ nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) #endif #define PROC(proc, argtype, restype) \ -[NFSPROC4_CLNT_##proc] = { \ +[NFSPROC4_CLNT_##proc] = { \ .p_proc = NFSPROC4_COMPOUND, \ .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \ .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 14314f089e8d..3d46a2caaade 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -105,6 +105,7 @@ struct nfs_openargs { struct qstr * name; struct nfs4_getattr * f_getattr; struct nfs4_getattr * d_getattr; + struct nfs_server * server; /* Needed for ID mapping */ }; struct nfs_openres { @@ -115,6 +116,7 @@ struct nfs_openres { __u32 rflags; struct nfs4_getattr * f_getattr; struct nfs4_getattr * d_getattr; + struct nfs_server * server; }; /* @@ -248,10 +250,12 @@ struct nfs_setattrargs { nfs4_stateid stateid; struct iattr * iap; struct nfs4_getattr * attr; + struct nfs_server * server; /* Needed for name mapping */ }; struct nfs_setattrres { struct nfs4_getattr * attr; + struct nfs_server * server; }; struct nfs_linkargs { -- cgit v1.2.3 From 3909ac8024931a6714f072ff4be6ded5c0ff6e71 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 7 Apr 2003 19:16:52 -0700 Subject: Make it more explicit that jiffies are "unsigned long", but that we for the initial value ctually want to check only wrap-around in an "unsigned int". --- include/linux/time.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/time.h b/include/linux/time.h index 7f5be084e342..4d7238025fe9 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -31,7 +31,7 @@ struct timezone { * Have the 32 bit jiffies value wrap 5 minutes after boot * so jiffies wrap bugs show up earlier. */ -#define INITIAL_JIFFIES ((unsigned int) (-300*HZ)) +#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) /* * Change timeval to jiffies, trying to avoid the -- cgit v1.2.3 From fd84584a663c92e90d526d7f44729d2ad5452767 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 7 Apr 2003 19:43:15 -0700 Subject: [PATCH] goodbye compatmac.h --- include/linux/compatmac.h | 160 ---------------------------------------------- 1 file changed, 160 deletions(-) delete mode 100644 include/linux/compatmac.h (limited to 'include/linux') diff --git a/include/linux/compatmac.h b/include/linux/compatmac.h deleted file mode 100644 index 5ae68a6b58e7..000000000000 --- a/include/linux/compatmac.h +++ /dev/null @@ -1,160 +0,0 @@ - /* - * This header tries to allow you to write 2.3-compatible drivers, - * but (using this header) still allows you to run them on 2.2 and - * 2.0 kernels. - * - * Sometimes, a #define replaces a "construct" that older kernels - * had. For example, - * - * DECLARE_MUTEX(name); - * - * replaces the older - * - * struct semaphore name = MUTEX; - * - * This file then declares the DECLARE_MUTEX macro to compile into the - * older version. - * - * In some cases, a macro or function changes the number of arguments. - * In that case, there is nothing we can do except define an access - * macro that provides the same functionality on both versions of Linux. - * - * This is the case for example with the "get_user" macro 2.0 kernels use: - * - * a = get_user (b); - * - * while newer kernels use - * - * get_user (a,b); - * - * This is unfortunate. We therefore define "Get_user (a,b)" which looks - * almost the same as the 2.2+ construct, and translates into the - * appropriate sequence for earlier constructs. - * - * Supported by this file are the 2.0 kernels, 2.2 kernels, and the - * most recent 2.3 kernel. 2.3 support will be dropped as soon when 2.4 - * comes out. 2.0 support may someday be dropped. But then again, maybe - * not. - * - * I'll try to maintain this, provided that Linus agrees with the setup. - * Feel free to mail updates or suggestions. - * - * -- R.E.Wolff@BitWizard.nl - * - */ - -#ifndef COMPATMAC_H -#define COMPATMAC_H - -#include - -#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */ -#define TWO_ZERO -#else -#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */ -#warning "Please use a 2.2.x kernel. " -#else -#if LINUX_VERSION_CODE < 0x020300 /* less than 2.3.x */ -#define TWO_TWO -#else -#define TWO_THREE -#endif -#endif -#endif - -#ifdef TWO_ZERO - -/* Here is the section that makes the 2.2 compatible driver source - work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, - and provide for compatibility stuff here if possible. */ - -/* Some 200 days (on intel) */ -#define MAX_SCHEDULE_TIMEOUT ((long)(~0UL>>1)) - -#include - -#define Get_user(a,b) a = get_user(b) -#define Put_user(a,b) 0,put_user(a,b) -#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) - -static inline int copy_from_user(void *to,const void *from, int c) -{ - memcpy_fromfs(to, from, c); - return 0; -} - -#define pci_present pcibios_present -#define pci_read_config_word pcibios_read_config_word -#define pci_read_config_dword pcibios_read_config_dword - -static inline unsigned char get_irq (unsigned char bus, unsigned char fn) -{ - unsigned char t; - pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t); - return t; -} - -static inline void *ioremap(unsigned long base, long length) -{ - if (base < 0x100000) return (void *)base; - return vremap (base, length); -} - -#define my_iounmap(x, b) (((long)x<0x100000)?0:vfree ((void*)x)) - -#define tty_flip_buffer_push(tty) schedule_delayed_work(&tty->flip.work, 1) -#define signal_pending(current) (current->signal & ~current->blocked) -#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) -#define time_after(t1,t2) (((long)t1-t2) > 0) - - -#define test_and_set_bit(nr, addr) set_bit(nr, addr) -#define test_and_clear_bit(nr, addr) clear_bit(nr, addr) - -/* Not yet implemented on 2.0 */ -#define ASYNC_SPD_SHI -1 -#define ASYNC_SPD_WARP -1 - - -/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it - to the "name" field that does exist. As long as the assignments are - done in the right order, there is nothing to worry about. */ -#define driver_name name - -/* Should be in a header somewhere. They are in tty.h on 2.2 */ -#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */ -#define TTY_HW_COOK_IN 15 /* in hardware - output and input */ - -/* The return type of a "close" routine. */ -#define INT void -#define NO_ERROR /* Nothing */ - -#else - -/* The 2.2.x compatibility section. */ -#include - - -#define Get_user(a,b) get_user(a,b) -#define Put_user(a,b) put_user(a,b) -#define get_irq(pdev) pdev->irq - -#define INT int -#define NO_ERROR 0 - -#define my_iounmap(x,b) (iounmap((char *)(b))) - -#endif - -#ifndef TWO_THREE -/* These are new in 2.3. The source now uses 2.3 syntax, and here is - the compatibility define... */ -#define wait_queue_head_t struct wait_queue * -#define DECLARE_MUTEX(name) struct semaphore name = MUTEX -#define DECLARE_WAITQUEUE(wait, current) \ - struct wait_queue wait = { current, NULL } - -#endif - - -#endif -- cgit v1.2.3 From 808048f59f088aa94e10ac70fcbf7b7370242be6 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 7 Apr 2003 19:43:22 -0700 Subject: [PATCH] update dvb headers --- include/linux/dvb/audio.h | 17 ++--- include/linux/dvb/ca.h | 21 ++++--- include/linux/dvb/dmx.h | 18 ++++-- include/linux/dvb/frontend.h | 36 ++++++----- include/linux/dvb/net.h | 1 + include/linux/dvb/osd.h | 144 +++++++++++++++++++++---------------------- include/linux/dvb/video.h | 1 + 7 files changed, 129 insertions(+), 109 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h index d0ce5e27bcd5..58956c3bba52 100644 --- a/include/linux/dvb/audio.h +++ b/include/linux/dvb/audio.h @@ -47,10 +47,17 @@ typedef enum { typedef enum { AUDIO_STEREO, AUDIO_MONO_LEFT, - AUDIO_MONO_RIGHT, + AUDIO_MONO_RIGHT } audio_channel_select_t; +typedef struct audio_mixer { + unsigned int volume_left; + unsigned int volume_right; + // what else do we need? bass, pass-through, ... +} audio_mixer_t; + + typedef struct audio_status { int AV_sync_state; /* sync audio and video? */ int mute_state; /* audio is muted */ @@ -58,16 +65,10 @@ typedef struct audio_status { audio_stream_source_t stream_source; /* current stream source */ audio_channel_select_t channel_select; /* currently selected channel */ int bypass_mode; /* pass on audio data to */ + audio_mixer_t mixer_state; /* current mixer state */ } audio_status_t; /* separate decoder hardware */ -typedef struct audio_mixer { - unsigned int volume_left; - unsigned int volume_right; - // what else do we need? bass, pass-through, ... -} audio_mixer_t; - - typedef struct audio_karaoke{ /* if Vocal1 or Vocal2 are non-zero, they get mixed */ int vocal1; /* into left and right t at 70% each */ diff --git a/include/linux/dvb/ca.h b/include/linux/dvb/ca.h index a0bdd645c745..026e5c35c0ab 100644 --- a/include/linux/dvb/ca.h +++ b/include/linux/dvb/ca.h @@ -21,8 +21,8 @@ * */ -#ifndef _CA_H_ -#define _CA_H_ +#ifndef _DVBCA_H_ +#define _DVBCA_H_ /* slot interface types and info */ @@ -33,6 +33,7 @@ typedef struct ca_slot_info { #define CA_CI 1 /* CI high level interface */ #define CA_CI_LINK 2 /* CI link layer level interface */ #define CA_CI_PHYS 4 /* CI physical layer level interface */ +#define CA_DESCR 8 /* built-in descrambler */ #define CA_SC 128 /* simple smart card interface */ unsigned int flags; @@ -44,7 +45,7 @@ typedef struct ca_slot_info { /* descrambler types and info */ typedef struct ca_descr_info { - unsigned int num; /* number of available descramblers (keys) */ + unsigned int num; /* number of available descramblers (keys) */ unsigned int type; /* type of supported scrambling system */ #define CA_ECD 1 #define CA_NDS 2 @@ -59,19 +60,24 @@ typedef struct ca_caps { } ca_caps_t; /* a message to/from a CI-CAM */ -typedef struct ca_msg { - unsigned int index; +typedef struct ca_msg { + unsigned int index; unsigned int type; unsigned int length; unsigned char msg[256]; } ca_msg_t; typedef struct ca_descr { - unsigned int index; - unsigned int parity; + unsigned int index; + unsigned int parity; /* 0 == even, 1 == odd */ unsigned char cw[8]; } ca_descr_t; +typedef struct ca_pid { + unsigned int pid; + int index; /* -1 == disable*/ +} ca_pid_t; + #define CA_RESET _IO('o', 128) #define CA_GET_CAP _IOR('o', 129, ca_caps_t) #define CA_GET_SLOT_INFO _IOR('o', 130, ca_slot_info_t) @@ -79,6 +85,7 @@ typedef struct ca_descr { #define CA_GET_MSG _IOR('o', 132, ca_msg_t) #define CA_SEND_MSG _IOW('o', 133, ca_msg_t) #define CA_SET_DESCR _IOW('o', 134, ca_descr_t) +#define CA_SET_PID _IOW('o', 135, ca_pid_t) #endif diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h index 38586a88ac3f..089b21734780 100644 --- a/include/linux/dvb/dmx.h +++ b/include/linux/dvb/dmx.h @@ -21,13 +21,14 @@ * */ -#ifndef _DMX_H_ -#define _DMX_H_ +#ifndef _DVBDMX_H_ +#define _DVBDMX_H_ #ifdef __KERNEL__ #include #else #include +#include #endif #define DMX_FILTER_SIZE 16 @@ -154,9 +155,15 @@ typedef enum { DMX_SOURCE_DVR0 = 16, DMX_SOURCE_DVR1, DMX_SOURCE_DVR2, - DMX_SOURCE_DVR3, + DMX_SOURCE_DVR3 } dmx_source_t; +struct dmx_stc { + unsigned int num; /* input : which STC? 0..N */ + unsigned int base; /* output: divisor for stc to get 90 kHz clock */ + uint64_t stc; /* output: stc in 'base'*90 kHz units */ +}; + #define DMX_START _IO('o',41) #define DMX_STOP _IO('o',42) @@ -164,9 +171,10 @@ typedef enum { #define DMX_SET_PES_FILTER _IOW('o',44,struct dmx_pes_filter_params) #define DMX_SET_BUFFER_SIZE _IO('o',45) #define DMX_GET_EVENT _IOR('o',46,struct dmx_event) -#define DMX_GET_PES_PIDS _IOR('o',47,uint16_t) +#define DMX_GET_PES_PIDS _IOR('o',47,uint16_t[5]) #define DMX_GET_CAPS _IOR('o',48,dmx_caps_t) #define DMX_SET_SOURCE _IOW('o',49,dmx_source_t) +#define DMX_GET_STC _IOWR('o',50,struct dmx_stc) -#endif /*_DMX_H_*/ +#endif /*_DVBDMX_H_*/ diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index 0256741c580b..8b17d6c2ea05 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -23,8 +23,8 @@ * */ -#ifndef _FRONTEND_H_ -#define _FRONTEND_H_ +#ifndef _DVBFRONTEND_H_ +#define _DVBFRONTEND_H_ #ifdef __KERNEL__ #include @@ -33,14 +33,14 @@ #endif -typedef enum { +typedef enum fe_type { FE_QPSK, FE_QAM, FE_OFDM } fe_type_t; -typedef enum { +typedef enum fe_caps { FE_IS_STUPID = 0, FE_CAN_INVERSION_AUTO = 0x1, FE_CAN_FEC_1_2 = 0x2, @@ -63,6 +63,8 @@ typedef enum { FE_CAN_BANDWIDTH_AUTO = 0x40000, FE_CAN_GUARD_INTERVAL_AUTO = 0x80000, FE_CAN_HIERARCHY_AUTO = 0x100000, + FE_CAN_RECOVER = 0x20000000, + FE_CAN_CLEAN_SETUP = 0x40000000, FE_CAN_MUTE_TS = 0x80000000 } fe_caps_t; @@ -99,25 +101,25 @@ struct dvb_diseqc_slave_reply { }; /* errorcode when no message was received */ -typedef enum { +typedef enum fe_sec_voltage { SEC_VOLTAGE_13, SEC_VOLTAGE_18 } fe_sec_voltage_t; -typedef enum { +typedef enum fe_sec_tone_mode { SEC_TONE_ON, SEC_TONE_OFF } fe_sec_tone_mode_t; -typedef enum { +typedef enum fe_sec_mini_cmd { SEC_MINI_A, SEC_MINI_B } fe_sec_mini_cmd_t; -typedef enum { +typedef enum fe_status { FE_HAS_SIGNAL = 0x01, /* found something above the noise level */ FE_HAS_CARRIER = 0x02, /* found a DVB signal */ FE_HAS_VITERBI = 0x04, /* FEC is stable */ @@ -125,17 +127,17 @@ typedef enum { FE_HAS_LOCK = 0x10, /* everything's working... */ FE_TIMEDOUT = 0x20, /* no lock within the last ~2 seconds */ FE_REINIT = 0x40 /* frontend was reinitialized, */ -} fe_status_t; /* application is recommned to reset */ +} fe_status_t; /* application is recommended to reset */ /* DiSEqC, tone and parameters */ -typedef enum { +typedef enum fe_spectral_inversion { INVERSION_OFF, INVERSION_ON, INVERSION_AUTO } fe_spectral_inversion_t; -typedef enum { +typedef enum fe_code_rate { FEC_NONE = 0, FEC_1_2, FEC_2_3, @@ -149,7 +151,7 @@ typedef enum { } fe_code_rate_t; -typedef enum { +typedef enum fe_modulation { QPSK, QAM_16, QAM_32, @@ -160,13 +162,13 @@ typedef enum { } fe_modulation_t; -typedef enum { +typedef enum fe_transmit_mode { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, TRANSMISSION_MODE_AUTO } fe_transmit_mode_t; -typedef enum { +typedef enum fe_bandwidth { BANDWIDTH_8_MHZ, BANDWIDTH_7_MHZ, BANDWIDTH_6_MHZ, @@ -174,7 +176,7 @@ typedef enum { } fe_bandwidth_t; -typedef enum { +typedef enum fe_guard_interval { GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_8, @@ -183,7 +185,7 @@ typedef enum { } fe_guard_interval_t; -typedef enum { +typedef enum fe_hierarchy { HIERARCHY_NONE, HIERARCHY_1, HIERARCHY_2, @@ -257,5 +259,5 @@ struct dvb_frontend_event { #define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event) -#endif /*_FRONTEND_H_*/ +#endif /*_DVBFRONTEND_H_*/ diff --git a/include/linux/dvb/net.h b/include/linux/dvb/net.h index 419d44884b72..5bf03b81e668 100644 --- a/include/linux/dvb/net.h +++ b/include/linux/dvb/net.h @@ -39,6 +39,7 @@ struct dvb_net_if { #define NET_ADD_IF _IOWR('o', 52, struct dvb_net_if) #define NET_REMOVE_IF _IO('o', 53) +#define NET_GET_IF _IOWR('o', 54, struct dvb_net_if) #endif /*_DVBNET_H_*/ diff --git a/include/linux/dvb/osd.h b/include/linux/dvb/osd.h index 760ccff6c75c..0d8143960a19 100644 --- a/include/linux/dvb/osd.h +++ b/include/linux/dvb/osd.h @@ -25,83 +25,83 @@ #define _DVBOSD_H_ typedef enum { - // All functions return -2 on "not open" + // All functions return -2 on "not open" OSD_Close=1, // () - // Disables OSD and releases the buffers - // returns 0 on success - OSD_Open, // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) - // Opens OSD with this size and bit depth - // returns 0 on success, -1 on DRAM allocation error, -2 on "already open" - OSD_Show, // () - // enables OSD mode - // returns 0 on success - OSD_Hide, // () - // disables OSD mode - // returns 0 on success - OSD_Clear, // () - // Sets all pixel to color 0 - // returns 0 on success - OSD_Fill, // (color) - // Sets all pixel to color - // returns 0 on success - OSD_SetColor, // (color,R{x0},G{y0},B{x1},opacity{y1}) - // set palette entry to , and apply - // R,G,B: 0..255 - // R=Red, G=Green, B=Blue - // opacity=0: pixel opacity 0% (only video pixel shows) - // opacity=1..254: pixel opacity as specified in header - // opacity=255: pixel opacity 100% (only OSD pixel shows) - // returns 0 on success, -1 on error - OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data) - // Set a number of entries in the palette - // sets the entries "firstcolor" through "lastcolor" from the array "data" - // data has 4 byte for each color: - // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel - OSD_SetTrans, // (transparency{color}) - // Sets transparency of mixed pixel (0..15) - // returns 0 on success - OSD_SetPixel, // (x0,y0,color) - // sets pixel , to color number - // returns 0 on success, -1 on error - OSD_GetPixel, // (x0,y0) - // returns color number of pixel ,, or -1 - OSD_SetRow, // (x0,y0,x1,data) - // fills pixels x0,y through x1,y with the content of data[] - // returns 0 on success, -1 on clipping all pixel (no pixel drawn) - OSD_SetBlock, // (x0,y0,x1,y1,increment{color},data) - // fills pixels x0,y0 through x1,y1 with the content of data[] - // inc contains the width of one line in the data block, - // inc<=0 uses blockwidth as linewidth - // returns 0 on success, -1 on clipping all pixel - OSD_FillRow, // (x0,y0,x1,color) - // fills pixels x0,y through x1,y with the color - // returns 0 on success, -1 on clipping all pixel - OSD_FillBlock, // (x0,y0,x1,y1,color) - // fills pixels x0,y0 through x1,y1 with the color - // returns 0 on success, -1 on clipping all pixel - OSD_Line, // (x0,y0,x1,y1,color) - // draw a line from x0,y0 to x1,y1 with the color - // returns 0 on success - OSD_Query, // (x0,y0,x1,y1,xasp{color}}), yasp=11 - // fills parameters with the picture dimensions and the pixel aspect ratio - // returns 0 on success - OSD_Test, // () - // draws a test picture. for debugging purposes only - // returns 0 on success + // Disables OSD and releases the buffers + // returns 0 on success + OSD_Open, // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) + // Opens OSD with this size and bit depth + // returns 0 on success, -1 on DRAM allocation error, -2 on "already open" + OSD_Show, // () + // enables OSD mode + // returns 0 on success + OSD_Hide, // () + // disables OSD mode + // returns 0 on success + OSD_Clear, // () + // Sets all pixel to color 0 + // returns 0 on success + OSD_Fill, // (color) + // Sets all pixel to color + // returns 0 on success + OSD_SetColor, // (color,R{x0},G{y0},B{x1},opacity{y1}) + // set palette entry to , and apply + // R,G,B: 0..255 + // R=Red, G=Green, B=Blue + // opacity=0: pixel opacity 0% (only video pixel shows) + // opacity=1..254: pixel opacity as specified in header + // opacity=255: pixel opacity 100% (only OSD pixel shows) + // returns 0 on success, -1 on error + OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data) + // Set a number of entries in the palette + // sets the entries "firstcolor" through "lastcolor" from the array "data" + // data has 4 byte for each color: + // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel + OSD_SetTrans, // (transparency{color}) + // Sets transparency of mixed pixel (0..15) + // returns 0 on success + OSD_SetPixel, // (x0,y0,color) + // sets pixel , to color number + // returns 0 on success, -1 on error + OSD_GetPixel, // (x0,y0) + // returns color number of pixel ,, or -1 + OSD_SetRow, // (x0,y0,x1,data) + // fills pixels x0,y through x1,y with the content of data[] + // returns 0 on success, -1 on clipping all pixel (no pixel drawn) + OSD_SetBlock, // (x0,y0,x1,y1,increment{color},data) + // fills pixels x0,y0 through x1,y1 with the content of data[] + // inc contains the width of one line in the data block, + // inc<=0 uses blockwidth as linewidth + // returns 0 on success, -1 on clipping all pixel + OSD_FillRow, // (x0,y0,x1,color) + // fills pixels x0,y through x1,y with the color + // returns 0 on success, -1 on clipping all pixel + OSD_FillBlock, // (x0,y0,x1,y1,color) + // fills pixels x0,y0 through x1,y1 with the color + // returns 0 on success, -1 on clipping all pixel + OSD_Line, // (x0,y0,x1,y1,color) + // draw a line from x0,y0 to x1,y1 with the color + // returns 0 on success + OSD_Query, // (x0,y0,x1,y1,xasp{color}}), yasp=11 + // fills parameters with the picture dimensions and the pixel aspect ratio + // returns 0 on success + OSD_Test, // () + // draws a test picture. for debugging purposes only + // returns 0 on success // TODO: remove "test" in final version - OSD_Text, // (x0,y0,size,color,text) - OSD_SetWindow, // (x0) set window with number 0 #else #include +#include #endif -- cgit v1.2.3 From c06e130bc0e062007e7f08222663379afa4bab99 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 7 Apr 2003 19:43:30 -0700 Subject: [PATCH] possible way to clean up fdreg.h --- include/linux/fdreg.h | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fdreg.h b/include/linux/fdreg.h index 1d9026eed978..c2eeb63b72db 100644 --- a/include/linux/fdreg.h +++ b/include/linux/fdreg.h @@ -7,8 +7,12 @@ */ #ifdef FDPATCHES - #define FD_IOPORT fdc_state[fdc].address +#else +/* It would be a lot saner just to force fdc_state[fdc].address to always + be set ! FIXME */ +#define FD_IOPORT 0x3f0 +#endif /* Fd controller regs. S&C, about page 340 */ #define FD_STATUS (4 + FD_IOPORT ) @@ -23,16 +27,6 @@ /* Diskette Control Register (write)*/ #define FD_DCR (7 + FD_IOPORT ) -#else - -#define FD_STATUS 0x3f4 -#define FD_DATA 0x3f5 -#define FD_DOR 0x3f2 /* Digital Output Register */ -#define FD_DIR 0x3f7 /* Digital Input Register (read) */ -#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/ - -#endif - /* Bits of main status register */ #define STATUS_BUSYMASK 0x0F /* drive busy mask */ #define STATUS_BUSY 0x10 /* FDC busy */ -- cgit v1.2.3 From d952d0b718ddc93619975c5ea148e288fbdd5302 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 7 Apr 2003 19:43:39 -0700 Subject: [PATCH] hdreg.h typo fix --- include/linux/hdreg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index 5b1c363f89cb..29e0e40b7167 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -355,7 +355,7 @@ typedef struct hd_drive_hob_hdr { #define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */ #define SETFEATURES_DIS_RETRY 0x33 /* Disable Retry */ #define SETFEATURES_EN_AAM 0x42 /* Enable Automatic Acoustic Management */ -#define SETFEATURES_RW_LONG 0x44 /* Set Lenght of VS bytes */ +#define SETFEATURES_RW_LONG 0x44 /* Set Length of VS bytes */ #define SETFEATURES_SET_CACHE 0x54 /* Set Cache segments to SC Reg. Val */ #define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */ #define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */ -- cgit v1.2.3 From 309b1d32729df0a900610bcf6f50a55ea1bef704 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 7 Apr 2003 19:43:46 -0700 Subject: [PATCH] continued compatmac exterminations --- include/linux/mtd/compatmac.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mtd/compatmac.h b/include/linux/mtd/compatmac.h index 19e6d2f849d5..8b243674cf22 100644 --- a/include/linux/mtd/compatmac.h +++ b/include/linux/mtd/compatmac.h @@ -17,7 +17,6 @@ #ifndef __LINUX_MTD_COMPATMAC_H__ #define __LINUX_MTD_COMPATMAC_H__ -#include #include /* used later in this header */ #include #ifndef LINUX_VERSION_CODE -- cgit v1.2.3 From 1a0ecaa9ffd7265fc629342e9a56059aa2b82c49 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 7 Apr 2003 19:43:54 -0700 Subject: [PATCH] lock for scc drivers --- include/linux/scc.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/scc.h b/include/linux/scc.h index c0f31c2caab0..4965e146b737 100644 --- a/include/linux/scc.h +++ b/include/linux/scc.h @@ -244,6 +244,9 @@ struct scc_channel { /* Timer */ struct timer_list tx_t; /* tx timer for this channel */ struct timer_list tx_wdog; /* tx watchdogs */ + + /* Channel lock */ + spinlock_t lock; /* Channel guard lock */ }; #endif /* defined(__KERNEL__) */ -- cgit v1.2.3 From 15b1d32152d8df09ddf22e044b494335af8fd7f1 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 7 Apr 2003 22:31:46 -0700 Subject: [PATCH] Fix futexes in hugetlb pages There is a stunning bug. --- include/linux/mm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index c6c2eef39d62..5f4bf646e187 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -231,8 +231,8 @@ static inline void get_page(struct page *page) static inline void put_page(struct page *page) { if (PageCompound(page)) { + page = (struct page *)page->lru.next; if (put_page_testzero(page)) { - page = (struct page *)page->lru.next; if (page->lru.prev) { /* destructor? */ (*(void (*)(struct page *))page->lru.prev)(page); } else { -- cgit v1.2.3 From 475cd853695f577664e20e4a907bf8b0a5740af0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 8 Apr 2003 03:10:42 -0700 Subject: Add __user/__kernel address space modifiers. When not checking, these end up being no-ops, but they get enabled by the type checker as special address_space attributes. --- include/linux/compiler.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux') diff --git a/include/linux/compiler.h b/include/linux/compiler.h index a28d0d51b851..6cbab5a2c88b 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -1,6 +1,14 @@ #ifndef __LINUX_COMPILER_H #define __LINUX_COMPILER_H +#ifdef __CHECKER__ + #define __user __attribute__((address_space(1))) + #define __kernel /* default address space */ +#else + #define __user + #define __kernel +#endif + #if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) #define inline __inline__ __attribute__((always_inline)) #define __inline__ __inline__ __attribute__((always_inline)) -- cgit v1.2.3 From d97a291ae962841478653e00c9fce35d16c41d36 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 8 Apr 2003 21:15:49 -0700 Subject: User pointers are not just in another address space, they also must never be dereferenced directly. Make that clear in the attribute. --- include/linux/compiler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 6cbab5a2c88b..4ef20f517d27 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -2,7 +2,7 @@ #define __LINUX_COMPILER_H #ifdef __CHECKER__ - #define __user __attribute__((address_space(1))) + #define __user __attribute__((noderef, address_space(1))) #define __kernel /* default address space */ #else #define __user -- cgit v1.2.3 From 596c3a20754aea9470b4a92cec925d0feeca50c7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 8 Apr 2003 21:29:58 -0700 Subject: [PATCH] remove nr_reverse_maps VM accounting Maintaining the `nr_reverse_maps' provides makes a small but measurable decrease in page_add_rmap() overhead. I don't think it's a very useful metric, and it can be sort-of inferred from slabinfo. --- fs/proc/proc_misc.c | 6 ++---- include/linux/page-flags.h | 1 - mm/page_alloc.c | 1 - mm/rmap.c | 7 ------- 4 files changed, 2 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index fbcef00a6e8d..af764fe47c6c 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -177,8 +177,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off, "Mapped: %8lu kB\n" "Slab: %8lu kB\n" "Committed_AS: %8u kB\n" - "PageTables: %8lu kB\n" - "ReverseMaps: %8lu\n", + "PageTables: %8lu kB\n", K(i.totalram), K(i.freeram), K(i.bufferram), @@ -197,8 +196,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off, K(ps.nr_mapped), K(ps.nr_slab), K(committed), - K(ps.nr_page_table_pages), - ps.nr_reverse_maps + K(ps.nr_page_table_pages) ); len += hugetlb_report_meminfo(page + len); diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index efe51537c564..b4d254418509 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -83,7 +83,6 @@ struct page_state { unsigned long nr_dirty; /* Dirty writeable pages */ unsigned long nr_writeback; /* Pages under writeback */ unsigned long nr_page_table_pages;/* Pages used for pagetables */ - unsigned long nr_reverse_maps; /* includes PageDirect */ unsigned long nr_mapped; /* mapped into pagetables */ unsigned long nr_slab; /* In slab */ #define GET_PAGE_STATE_LAST nr_slab diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 7f142ff2e77e..f2e5ffc3de32 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1432,7 +1432,6 @@ static char *vmstat_text[] = { "nr_dirty", "nr_writeback", "nr_page_table_pages", - "nr_reverse_maps", "nr_mapped", "nr_slab", diff --git a/mm/rmap.c b/mm/rmap.c index 031fa08978ab..61a6158f21b4 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -209,8 +209,6 @@ page_add_rmap(struct page *page, pte_t *ptep, struct pte_chain *pte_chain) goto out; } - BUG_ON(!cur_pte_chain->ptes[NRPTE-1]); - for (i = NRPTE-2; i >= 0; i--) { if (!cur_pte_chain->ptes[i]) { cur_pte_chain->ptes[i] = pte_paddr; @@ -220,7 +218,6 @@ page_add_rmap(struct page *page, pte_t *ptep, struct pte_chain *pte_chain) BUG(); out: pte_chain_unlock(page); - inc_page_state(nr_reverse_maps); return pte_chain; } @@ -251,7 +248,6 @@ void page_remove_rmap(struct page * page, pte_t * ptep) if (PageDirect(page)) { if (page->pte.direct == pte_paddr) { page->pte.direct = 0; - dec_page_state(nr_reverse_maps); ClearPageDirect(page); goto out; } @@ -274,7 +270,6 @@ void page_remove_rmap(struct page * page, pte_t * ptep) if (pa != pte_paddr) continue; pc->ptes[i] = start->ptes[victim_i]; - dec_page_state(nr_reverse_maps); start->ptes[victim_i] = 0; if (victim_i == NRPTE-1) { /* Emptied a pte_chain */ @@ -435,7 +430,6 @@ int try_to_unmap(struct page * page) ret = try_to_unmap_one(page, page->pte.direct); if (ret == SWAP_SUCCESS) { page->pte.direct = 0; - dec_page_state(nr_reverse_maps); ClearPageDirect(page); } goto out; @@ -466,7 +460,6 @@ int try_to_unmap(struct page * page) */ pc->ptes[i] = start->ptes[victim_i]; start->ptes[victim_i] = 0; - dec_page_state(nr_reverse_maps); victim_i++; if (victim_i == NRPTE) { page->pte.chain = start->next; -- cgit v1.2.3 From 8e98702b845d48b79418c2eebf60badcb2ef22c0 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 8 Apr 2003 21:30:24 -0700 Subject: [PATCH] Replace the radix-tree rwlock with a spinlock Spinlocks don't have a buslocked unlock and are faster. On a P4, time to write a 4M file with 4M one-byte-write()s: Before: 0.72s user 5.47s system 99% cpu 6.227 total 0.76s user 5.40s system 100% cpu 6.154 total 0.77s user 5.38s system 100% cpu 6.146 total After: 1.09s user 4.92s system 99% cpu 6.014 total 0.74s user 5.28s system 99% cpu 6.023 total 1.03s user 4.97s system 100% cpu 5.991 total --- fs/fs-writeback.c | 4 ++-- fs/inode.c | 2 +- fs/mpage.c | 8 ++++---- include/linux/fs.h | 2 +- mm/filemap.c | 42 +++++++++++++++++++++--------------------- mm/page-writeback.c | 14 +++++++------- mm/readahead.c | 8 ++++---- mm/swap_state.c | 22 +++++++++++----------- mm/swapfile.c | 8 ++++---- mm/truncate.c | 6 +++--- mm/vmscan.c | 14 +++++++------- 11 files changed, 65 insertions(+), 65 deletions(-) (limited to 'include/linux') diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index e4559dc8fc1c..a48d3b829479 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -149,10 +149,10 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) * read speculatively by this cpu before &= ~I_DIRTY -- mikulas */ - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); if (wait || !wbc->for_kupdate || list_empty(&mapping->io_pages)) list_splice_init(&mapping->dirty_pages, &mapping->io_pages); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); spin_unlock(&inode_lock); do_writepages(mapping, wbc); diff --git a/fs/inode.c b/fs/inode.c index ea88c310de87..364901cdf901 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -181,7 +181,7 @@ void inode_init_once(struct inode *inode) INIT_LIST_HEAD(&inode->i_devices); sema_init(&inode->i_sem, 1); INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); - rwlock_init(&inode->i_data.page_lock); + spin_lock_init(&inode->i_data.page_lock); init_MUTEX(&inode->i_data.i_shared_sem); INIT_LIST_HEAD(&inode->i_data.private_list); spin_lock_init(&inode->i_data.private_lock); diff --git a/fs/mpage.c b/fs/mpage.c index 45f79b8da045..2c91d7c55e10 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -627,7 +627,7 @@ mpage_writepages(struct address_space *mapping, writepage = mapping->a_ops->writepage; pagevec_init(&pvec, 0); - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); while (!list_empty(&mapping->io_pages) && !done) { struct page *page = list_entry(mapping->io_pages.prev, struct page, list); @@ -647,7 +647,7 @@ mpage_writepages(struct address_space *mapping, list_add(&page->list, &mapping->locked_pages); page_cache_get(page); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); /* * At this point we hold neither mapping->page_lock nor @@ -679,12 +679,12 @@ mpage_writepages(struct address_space *mapping, unlock_page(page); } page_cache_release(page); - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); } /* * Leave any remaining dirty pages on ->io_pages */ - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); if (bio) mpage_bio_submit(WRITE, bio); return ret; diff --git a/include/linux/fs.h b/include/linux/fs.h index af3852b4281d..158edfbd69f1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -313,7 +313,7 @@ struct backing_dev_info; struct address_space { struct inode *host; /* owner: inode, block_device */ struct radix_tree_root page_tree; /* radix tree of all pages */ - rwlock_t page_lock; /* and rwlock protecting it */ + spinlock_t page_lock; /* and rwlock protecting it */ struct list_head clean_pages; /* list of clean pages */ struct list_head dirty_pages; /* list of dirty pages */ struct list_head locked_pages; /* list of locked pages */ diff --git a/mm/filemap.c b/mm/filemap.c index 65d10150f68c..071171245d4a 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -99,9 +99,9 @@ void remove_from_page_cache(struct page *page) if (unlikely(!PageLocked(page))) PAGE_BUG(page); - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); __remove_from_page_cache(page); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); } static inline int sync_page(struct page *page) @@ -133,9 +133,9 @@ static int __filemap_fdatawrite(struct address_space *mapping, int sync_mode) if (mapping->backing_dev_info->memory_backed) return 0; - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); list_splice_init(&mapping->dirty_pages, &mapping->io_pages); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); ret = do_writepages(mapping, &wbc); return ret; } @@ -166,7 +166,7 @@ int filemap_fdatawait(struct address_space * mapping) restart: progress = 0; - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); while (!list_empty(&mapping->locked_pages)) { struct page *page; @@ -180,7 +180,7 @@ restart: if (!PageWriteback(page)) { if (++progress > 32) { if (need_resched()) { - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); __cond_resched(); goto restart; } @@ -190,16 +190,16 @@ restart: progress = 0; page_cache_get(page); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); wait_on_page_writeback(page); if (PageError(page)) ret = -EIO; page_cache_release(page); - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); } - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); return ret; } @@ -227,7 +227,7 @@ int add_to_page_cache(struct page *page, struct address_space *mapping, if (error == 0) { page_cache_get(page); - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); error = radix_tree_insert(&mapping->page_tree, offset, page); if (!error) { SetPageLocked(page); @@ -235,7 +235,7 @@ int add_to_page_cache(struct page *page, struct address_space *mapping, } else { page_cache_release(page); } - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); radix_tree_preload_end(); } return error; @@ -364,11 +364,11 @@ struct page * find_get_page(struct address_space *mapping, unsigned long offset) * We scan the hash list read-only. Addition to and removal from * the hash-list needs a held write-lock. */ - read_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page) page_cache_get(page); - read_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); return page; } @@ -379,11 +379,11 @@ struct page *find_trylock_page(struct address_space *mapping, unsigned long offs { struct page *page; - read_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page && TestSetPageLocked(page)) page = NULL; - read_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); return page; } @@ -403,15 +403,15 @@ struct page *find_lock_page(struct address_space *mapping, { struct page *page; - read_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); repeat: page = radix_tree_lookup(&mapping->page_tree, offset); if (page) { page_cache_get(page); if (TestSetPageLocked(page)) { - read_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); lock_page(page); - read_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); /* Has the page been truncated while we slept? */ if (page->mapping != mapping || page->index != offset) { @@ -421,7 +421,7 @@ repeat: } } } - read_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); return page; } @@ -491,12 +491,12 @@ unsigned int find_get_pages(struct address_space *mapping, pgoff_t start, unsigned int i; unsigned int ret; - read_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); ret = radix_tree_gang_lookup(&mapping->page_tree, (void **)pages, start, nr_pages); for (i = 0; i < ret; i++) page_cache_get(pages[i]); - read_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); return ret; } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 77d18b8b97aa..fc6f459bb83f 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -425,12 +425,12 @@ int write_one_page(struct page *page, int wait) if (wait && PageWriteback(page)) wait_on_page_writeback(page); - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); list_del(&page->list); if (test_clear_page_dirty(page)) { list_add(&page->list, &mapping->locked_pages); page_cache_get(page); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); ret = mapping->a_ops->writepage(page, &wbc); if (ret == 0 && wait) { wait_on_page_writeback(page); @@ -440,7 +440,7 @@ int write_one_page(struct page *page, int wait) page_cache_release(page); } else { list_add(&page->list, &mapping->clean_pages); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); unlock_page(page); } return ret; @@ -513,14 +513,14 @@ int __set_page_dirty_buffers(struct page *page) spin_unlock(&mapping->private_lock); if (!TestSetPageDirty(page)) { - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); if (page->mapping) { /* Race with truncate? */ if (!mapping->backing_dev_info->memory_backed) inc_page_state(nr_dirty); list_del(&page->list); list_add(&page->list, &mapping->dirty_pages); } - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } @@ -550,7 +550,7 @@ int __set_page_dirty_nobuffers(struct page *page) struct address_space *mapping = page->mapping; if (mapping) { - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); if (page->mapping) { /* Race with truncate? */ BUG_ON(page->mapping != mapping); if (!mapping->backing_dev_info->memory_backed) @@ -558,7 +558,7 @@ int __set_page_dirty_nobuffers(struct page *page) list_del(&page->list); list_add(&page->list, &mapping->dirty_pages); } - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } } diff --git a/mm/readahead.c b/mm/readahead.c index 14b9772eee79..0ba5344553ea 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -217,7 +217,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp, /* * Preallocate as many pages as we will need. */ - read_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); for (page_idx = 0; page_idx < nr_to_read; page_idx++) { unsigned long page_offset = offset + page_idx; @@ -228,16 +228,16 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp, if (page) continue; - read_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); page = page_cache_alloc_cold(mapping); - read_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); if (!page) break; page->index = page_offset; list_add(&page->list, &page_pool); ret++; } - read_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); /* * Now start the IO. We ignore I/O errors - if the page is not diff --git a/mm/swap_state.c b/mm/swap_state.c index 0af3a557d1fe..b479ebafa2bd 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -34,7 +34,7 @@ extern struct address_space_operations swap_aops; struct address_space swapper_space = { .page_tree = RADIX_TREE_INIT(GFP_ATOMIC), - .page_lock = RW_LOCK_UNLOCKED, + .page_lock = SPIN_LOCK_UNLOCKED, .clean_pages = LIST_HEAD_INIT(swapper_space.clean_pages), .dirty_pages = LIST_HEAD_INIT(swapper_space.dirty_pages), .io_pages = LIST_HEAD_INIT(swapper_space.io_pages), @@ -191,9 +191,9 @@ void delete_from_swap_cache(struct page *page) entry.val = page->index; - write_lock(&swapper_space.page_lock); + spin_lock(&swapper_space.page_lock); __delete_from_swap_cache(page); - write_unlock(&swapper_space.page_lock); + spin_unlock(&swapper_space.page_lock); swap_free(entry); page_cache_release(page); @@ -204,8 +204,8 @@ int move_to_swap_cache(struct page *page, swp_entry_t entry) struct address_space *mapping = page->mapping; int err; - write_lock(&swapper_space.page_lock); - write_lock(&mapping->page_lock); + spin_lock(&swapper_space.page_lock); + spin_lock(&mapping->page_lock); err = radix_tree_insert(&swapper_space.page_tree, entry.val, page); if (!err) { @@ -213,8 +213,8 @@ int move_to_swap_cache(struct page *page, swp_entry_t entry) ___add_to_page_cache(page, &swapper_space, entry.val); } - write_unlock(&mapping->page_lock); - write_unlock(&swapper_space.page_lock); + spin_unlock(&mapping->page_lock); + spin_unlock(&swapper_space.page_lock); if (!err) { if (!swap_duplicate(entry)) @@ -240,8 +240,8 @@ int move_from_swap_cache(struct page *page, unsigned long index, entry.val = page->index; - write_lock(&swapper_space.page_lock); - write_lock(&mapping->page_lock); + spin_lock(&swapper_space.page_lock); + spin_lock(&mapping->page_lock); err = radix_tree_insert(&mapping->page_tree, index, page); if (!err) { @@ -249,8 +249,8 @@ int move_from_swap_cache(struct page *page, unsigned long index, ___add_to_page_cache(page, mapping, index); } - write_unlock(&mapping->page_lock); - write_unlock(&swapper_space.page_lock); + spin_unlock(&mapping->page_lock); + spin_unlock(&swapper_space.page_lock); if (!err) { swap_free(entry); diff --git a/mm/swapfile.c b/mm/swapfile.c index b49e48f12c0c..97eb0960437d 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -248,10 +248,10 @@ static int exclusive_swap_page(struct page *page) /* Is the only swap cache user the cache itself? */ if (p->swap_map[swp_offset(entry)] == 1) { /* Recheck the page count with the pagecache lock held.. */ - read_lock(&swapper_space.page_lock); + spin_lock(&swapper_space.page_lock); if (page_count(page) - !!PagePrivate(page) == 2) retval = 1; - read_unlock(&swapper_space.page_lock); + spin_unlock(&swapper_space.page_lock); } swap_info_put(p); } @@ -319,13 +319,13 @@ int remove_exclusive_swap_page(struct page *page) retval = 0; if (p->swap_map[swp_offset(entry)] == 1) { /* Recheck the page count with the pagecache lock held.. */ - write_lock(&swapper_space.page_lock); + spin_lock(&swapper_space.page_lock); if ((page_count(page) == 2) && !PageWriteback(page)) { __delete_from_swap_cache(page); SetPageDirty(page); retval = 1; } - write_unlock(&swapper_space.page_lock); + spin_unlock(&swapper_space.page_lock); } swap_info_put(p); diff --git a/mm/truncate.c b/mm/truncate.c index 56bdd03b1576..8828e0e48bf0 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -73,13 +73,13 @@ invalidate_complete_page(struct address_space *mapping, struct page *page) if (PagePrivate(page) && !try_to_release_page(page, 0)) return 0; - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); if (PageDirty(page)) { - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); return 0; } __remove_from_page_cache(page); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); ClearPageUptodate(page); page_cache_release(page); /* pagecache ref */ return 1; diff --git a/mm/vmscan.c b/mm/vmscan.c index 407920e2831b..3d204f882d04 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -325,7 +325,7 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, goto keep_locked; if (!may_write_to_queue(mapping->backing_dev_info)) goto keep_locked; - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); if (test_clear_page_dirty(page)) { int res; struct writeback_control wbc = { @@ -336,7 +336,7 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, }; list_move(&page->list, &mapping->locked_pages); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); SetPageReclaim(page); res = mapping->a_ops->writepage(page, &wbc); @@ -351,7 +351,7 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, } goto keep; } - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); } /* @@ -385,7 +385,7 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, if (!mapping) goto keep_locked; /* truncate got there first */ - write_lock(&mapping->page_lock); + spin_lock(&mapping->page_lock); /* * The non-racy check for busy page. It is critical to check @@ -393,7 +393,7 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, * not in use by anybody. (pagecache + us == 2) */ if (page_count(page) != 2 || PageDirty(page)) { - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); goto keep_locked; } @@ -401,7 +401,7 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, if (PageSwapCache(page)) { swp_entry_t swap = { .val = page->index }; __delete_from_swap_cache(page); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); swap_free(swap); __put_page(page); /* The pagecache ref */ goto free_it; @@ -409,7 +409,7 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, #endif /* CONFIG_SWAP */ __remove_from_page_cache(page); - write_unlock(&mapping->page_lock); + spin_unlock(&mapping->page_lock); __put_page(page); free_it: -- cgit v1.2.3 From e1851a6c19fcbddc2cead061ee2916239f49b06f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 8 Apr 2003 21:30:52 -0700 Subject: [PATCH] JBD pasting warning fix From: "Hua Zhong" Fix a token-pasting warning from recent gcc's --- include/linux/jbd.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/jbd.h b/include/linux/jbd.h index 2cddeb1f450e..e00aec05a9b5 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -274,8 +274,9 @@ void buffer_assertion_failure(struct buffer_head *bh); #define __journal_expect(expr, why...) \ do { \ if (!(expr)) { \ - printk(KERN_ERR "EXT3-fs unexpected failure: %s;\n", # expr); \ - printk(KERN_ERR ## why); \ + printk(KERN_ERR \ + "EXT3-fs unexpected failure: %s;\n",# expr); \ + printk(KERN_ERR why); \ } \ } while (0) #define J_EXPECT(expr, why...) __journal_expect(expr, ## why) -- cgit v1.2.3 From 7b78878b47141bb38c217d3d354adb24eb499e34 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 8 Apr 2003 21:31:10 -0700 Subject: [PATCH] Allow panics and reboots at oops time. From: Russell Miller A BUG or an oops will often leave a machine in a useless state. There is no way to remotely recover the machine from that state. The patch adds a /proc/sys/kernel/panic_on_oops sysctl which, when set, will cause the x86 kernel to call panic() at the end of the oops handler. If the user has also set /proc/sys/kernel/panic then a reboot will occur. The implementation will try to sleep for a while before panicing so the oops info has a chance of hitting the logs. The implementation is designed so that other architectures can easily do this in their oops handlers. --- Documentation/sysctl/kernel.txt | 12 ++++++++++++ arch/i386/kernel/traps.c | 9 +++++++++ include/linux/kernel.h | 1 + include/linux/sysctl.h | 1 + kernel/panic.c | 7 +++---- kernel/sysctl.c | 2 ++ 6 files changed, 28 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index e6f061d1a2f7..74d52720ade6 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -204,6 +204,18 @@ software watchdog, the recommended setting is 60. ============================================================== +panic_on_oops: + +Controls the kernel's behaviour when an oops or BUG is encountered. + +0: try to continue operation + +1: delay a few seconds (to give klogd time to record the oops output) and + then panic. If the `panic' sysctl is also non-zero then the machine will + be rebooted. + +============================================================== + pid_max: PID allocation wrap value. When the kenrel's next PID value diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 79aa129a6bc4..53c610ea831c 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -257,6 +257,15 @@ void die(const char * str, struct pt_regs * regs, long err) show_registers(regs); bust_spinlocks(0); spin_unlock_irq(&die_lock); + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) { + printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(5 * HZ); + panic("Fatal exception"); + } do_exit(SIGSEGV); } diff --git a/include/linux/kernel.h b/include/linux/kernel.h index f7f83f129d9f..94d476e7d80f 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -104,6 +104,7 @@ static inline void console_verbose(void) extern void bust_spinlocks(int yes); extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */ +extern int panic_on_oops; extern int tainted; extern const char *print_tainted(void); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 29a5f877d0f3..f6a32a5dc496 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -129,6 +129,7 @@ enum KERN_CADPID=54, /* int: PID of the process to notify on CAD */ KERN_PIDMAX=55, /* int: PID # limit */ KERN_CORE_PATTERN=56, /* string: pattern for core-file names */ + KERN_PANIC_ON_OOPS=57, /* int: whether we will panic on an oops */ }; diff --git a/kernel/panic.c b/kernel/panic.c index 4f4e36663617..66a22b5d9c77 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -20,6 +20,8 @@ asmlinkage void sys_sync(void); /* it's really int */ int panic_timeout; +int panic_on_oops; +int tainted; struct notifier_block *panic_notifier_list; @@ -28,7 +30,6 @@ static int __init panic_setup(char *str) panic_timeout = simple_strtoul(str, NULL, 0); return 1; } - __setup("panic=", panic_setup); /** @@ -51,7 +52,7 @@ NORET_TYPE void panic(const char * fmt, ...) bust_spinlocks(1); va_start(args, fmt); - vsprintf(buf, fmt, args); + vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); printk(KERN_EMERG "Kernel panic: %s\n",buf); if (in_interrupt()) @@ -123,5 +124,3 @@ const char *print_tainted() snprintf(buf, sizeof(buf), "Not tainted"); return(buf); } - -int tainted = 0; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 27cd5c65124f..21381e2efa18 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -263,6 +263,8 @@ static ctl_table kern_table[] = { #endif {KERN_PIDMAX, "pid_max", &pid_max, sizeof (int), 0600, NULL, &proc_dointvec}, + {KERN_PANIC_ON_OOPS,"panic_on_oops", + &panic_on_oops,sizeof(int),0644,NULL,&proc_dointvec}, {0} }; -- cgit v1.2.3 From 598ee77158db8295edbd5e9d850e4e0fddbe9afc Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 8 Apr 2003 21:31:44 -0700 Subject: [PATCH] struct address_space comments From: "Martin J. Bligh" Fix the commentary around the address_space fields. --- include/linux/fs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index 158edfbd69f1..a3315d636032 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -321,8 +321,8 @@ struct address_space { unsigned long nrpages; /* number of total pages */ struct address_space_operations *a_ops; /* methods */ struct list_head i_mmap; /* list of private mappings */ - struct list_head i_mmap_shared; /* list of private mappings */ - struct semaphore i_shared_sem; /* and sem protecting it */ + struct list_head i_mmap_shared; /* list of shared mappings */ + struct semaphore i_shared_sem; /* protect both above lists */ unsigned long dirtied_when; /* jiffies of first page dirtying */ int gfp_mask; /* how to allocate the pages */ struct backing_dev_info *backing_dev_info; /* device readahead, etc */ -- cgit v1.2.3 From 52a4a8b77985bf6695d1506cf0af74b624dee41f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 8 Apr 2003 21:31:53 -0700 Subject: [PATCH] task_lock commentary fixes From: Manfred Spraul Update and clarify the incorrect commentary around task_lock() --- include/linux/sched.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index f3b4c5891898..bbc51fac0cf6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -686,7 +686,11 @@ static inline int thread_group_empty(task_t *p) extern void unhash_process(struct task_struct *p); -/* Protects ->fs, ->files, ->mm, and synchronises with wait4(). Nests inside tasklist_lock */ +/* Protects ->fs, ->files, ->mm, and synchronises with wait4(). + * Nests both inside and outside of read_lock(&tasklist_lock). + * It must not be nested with write_lock_irq(&tasklist_lock), + * neither inside nor outside. + */ static inline void task_lock(struct task_struct *p) { spin_lock(&p->alloc_lock); -- cgit v1.2.3 From b1d7a6ca11201bab3e1172d77b1fd05454f4f107 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 8 Apr 2003 21:44:19 -0700 Subject: Tag more user-supplied path strings as being user pointers for type evaluation. This tags the system call interfaces in fs/open.c, fs/dcache.c and mm/swapfile.c - and tags the path walking helper functions. --- fs/dcache.c | 2 +- fs/open.c | 32 ++++++++++++++++---------------- include/linux/fs.h | 2 +- include/linux/namei.h | 2 +- mm/swapfile.c | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/fs/dcache.c b/fs/dcache.c index 75c420bb8d97..efc51c38ea25 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1366,7 +1366,7 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, * return NULL; * } */ -asmlinkage long sys_getcwd(char *buf, unsigned long size) +asmlinkage long sys_getcwd(char __user *buf, unsigned long size) { int error; struct vfsmount *pwdmnt, *rootmnt; diff --git a/fs/open.c b/fs/open.c index 30aae79194d7..d56d61efe533 100644 --- a/fs/open.c +++ b/fs/open.c @@ -41,7 +41,7 @@ int vfs_statfs(struct super_block *sb, struct statfs *buf) } -asmlinkage long sys_statfs(const char * path, struct statfs * buf) +asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) { struct nameidata nd; int error; @@ -57,7 +57,7 @@ asmlinkage long sys_statfs(const char * path, struct statfs * buf) return error; } -asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf) +asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) { struct file * file; struct statfs tmp; @@ -92,7 +92,7 @@ int do_truncate(struct dentry *dentry, loff_t length) return err; } -static inline long do_sys_truncate(const char * path, loff_t length) +static inline long do_sys_truncate(const char __user * path, loff_t length) { struct nameidata nd; struct inode * inode; @@ -152,7 +152,7 @@ out: return error; } -asmlinkage long sys_truncate(const char * path, unsigned long length) +asmlinkage long sys_truncate(const char __user * path, unsigned long length) { /* on 32-bit boxen it will cut the range 2^31--2^32-1 off */ return do_sys_truncate(path, (long)length); @@ -208,7 +208,7 @@ asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length) /* LFS versions of truncate are only needed on 32 bit machines */ #if BITS_PER_LONG == 32 -asmlinkage long sys_truncate64(const char * path, loff_t length) +asmlinkage long sys_truncate64(const char __user * path, loff_t length) { return do_sys_truncate(path, length); } @@ -232,7 +232,7 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ -asmlinkage long sys_utime(char * filename, struct utimbuf * times) +asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) { int error; struct nameidata nd; @@ -280,7 +280,7 @@ out: * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ -long do_utimes(char * filename, struct timeval * times) +long do_utimes(char __user * filename, struct timeval __user * times) { int error; struct nameidata nd; @@ -319,7 +319,7 @@ out: return error; } -asmlinkage long sys_utimes(char * filename, struct timeval * utimes) +asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utimes) { struct timeval times[2]; @@ -334,7 +334,7 @@ asmlinkage long sys_utimes(char * filename, struct timeval * utimes) * We do this by temporarily clearing all FS-related capabilities and * switching the fsuid/fsgid around to the real ones. */ -asmlinkage long sys_access(const char * filename, int mode) +asmlinkage long sys_access(const char __user * filename, int mode) { struct nameidata nd; int old_fsuid, old_fsgid; @@ -381,7 +381,7 @@ asmlinkage long sys_access(const char * filename, int mode) return res; } -asmlinkage long sys_chdir(const char * filename) +asmlinkage long sys_chdir(const char __user * filename) { struct nameidata nd; int error; @@ -432,7 +432,7 @@ out: return error; } -asmlinkage long sys_chroot(const char * filename) +asmlinkage long sys_chroot(const char __user * filename) { struct nameidata nd; int error; @@ -493,7 +493,7 @@ out: return err; } -asmlinkage long sys_chmod(const char * filename, mode_t mode) +asmlinkage long sys_chmod(const char __user * filename, mode_t mode) { struct nameidata nd; struct inode * inode; @@ -562,7 +562,7 @@ out: return error; } -asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group) +asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) { struct nameidata nd; int error; @@ -575,7 +575,7 @@ asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group) return error; } -asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group) +asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) { struct nameidata nd; int error; @@ -793,7 +793,7 @@ void fd_install(unsigned int fd, struct file * file) write_unlock(&files->file_lock); } -asmlinkage long sys_open(const char * filename, int flags, int mode) +asmlinkage long sys_open(const char __user * filename, int flags, int mode) { char * tmp; int fd, error; @@ -829,7 +829,7 @@ out_error: * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ -asmlinkage long sys_creat(const char * pathname, int mode) +asmlinkage long sys_creat(const char __user * pathname, int mode) { return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); } diff --git a/include/linux/fs.h b/include/linux/fs.h index a3315d636032..16ad733f58e4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1024,7 +1024,7 @@ extern int do_truncate(struct dentry *, loff_t start); extern struct file *filp_open(const char *, int, int); extern struct file * dentry_open(struct dentry *, struct vfsmount *, int); extern int filp_close(struct file *, fl_owner_t id); -extern char * getname(const char *); +extern char * getname(const char __user *); /* fs/dcache.c */ extern void vfs_caches_init(unsigned long); diff --git a/include/linux/namei.h b/include/linux/namei.h index 9d5b102f9e9e..16baf5cdb9c7 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -33,7 +33,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_NOALT 32 -extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *)); +extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *)); #define user_path_walk(name,nd) \ __user_walk(name, LOOKUP_FOLLOW, nd) #define user_path_walk_link(name,nd) \ diff --git a/mm/swapfile.c b/mm/swapfile.c index e60b0fb2e321..8426b3e97464 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -995,7 +995,7 @@ int page_queue_congested(struct page *page) } #endif -asmlinkage long sys_swapoff(const char * specialfile) +asmlinkage long sys_swapoff(const char __user * specialfile) { struct swap_info_struct * p = NULL; unsigned short *swap_map; @@ -1199,7 +1199,7 @@ __initcall(procswaps_init); * * The swapon system call */ -asmlinkage long sys_swapon(const char * specialfile, int swap_flags) +asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) { struct swap_info_struct * p; char *name = NULL; -- cgit v1.2.3 From b9a8a0bdc30686d0064cadbc1f611fea47828db1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 9 Apr 2003 06:50:47 -0700 Subject: Annotate sysct with user pointer annotations --- include/linux/sysctl.h | 8 ++++---- kernel/sysctl.c | 51 +++++++++++++++++++++++++------------------------- 2 files changed, 30 insertions(+), 29 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index f6a32a5dc496..79b779f29c9f 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -679,8 +679,8 @@ extern void sysctl_init(void); typedef struct ctl_table ctl_table; typedef int ctl_handler (ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context); typedef int proc_handler (ctl_table *ctl, int write, struct file * filp, @@ -707,8 +707,8 @@ extern int do_sysctl (int *name, int nlen, extern int do_sysctl_strategy (ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void ** context); + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void ** context); extern ctl_handler sysctl_string; extern ctl_handler sysctl_intvec; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 21381e2efa18..aff65582bd21 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -403,7 +403,7 @@ int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp, return -ENOTDIR; } -extern asmlinkage long sys_sysctl(struct __sysctl_args *args) +asmlinkage long sys_sysctl(struct __sysctl_args __user *args) { struct __sysctl_args tmp; int error; @@ -444,8 +444,8 @@ static inline int ctl_perm(ctl_table *table, int op) } static int parse_table(int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, ctl_table *table, void **context) { int n; @@ -485,8 +485,8 @@ repeat: /* Perform the actual read/write of a sysctl table entry. */ int do_sysctl_strategy (ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) { int op = 0, rc; size_t len; @@ -787,10 +787,11 @@ static int proc_sys_permission(struct inode *inode, int op) * Returns 0 on success. */ int proc_dostring(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { size_t len; - char *p, c; + char __user *p; + char c; if (!table->data || !table->maxlen || !*lenp || (filp->f_pos && !write)) { @@ -840,7 +841,7 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, */ static int proc_doutsstring(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { int r; @@ -863,7 +864,7 @@ static int proc_doutsstring(ctl_table *table, int write, struct file *filp, #define OP_MIN 4 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp, int conv, int op) + void __user *buffer, size_t *lenp, int conv, int op) { int *i, vleft, first=1, neg, val; size_t left, len; @@ -885,12 +886,12 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, if (write) { while (left) { char c; - if(get_user(c,(char *) buffer)) + if (get_user(c,(char __user *) buffer)) return -EFAULT; if (!isspace(c)) break; left--; - ((char *) buffer)++; + buffer++; } if (!left) break; @@ -979,7 +980,7 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, * Returns 0 on success. */ int proc_dointvec(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET); } @@ -989,7 +990,7 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp, */ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { if (!capable(CAP_SYS_MODULE)) { return -EPERM; @@ -1015,7 +1016,7 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, * Returns 0 on success. */ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { int *i, *min, *max, vleft, first=1, neg, val; size_t len, left; @@ -1043,7 +1044,7 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, if (!isspace(c)) break; left--; - ((char *) buffer)++; + buffer++; } if (!left) break; @@ -1113,7 +1114,7 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, static int do_proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp, + void __user *buffer, size_t *lenp, unsigned long convmul, unsigned long convdiv) { @@ -1139,12 +1140,12 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write, if (write) { while (left) { char c; - if(get_user(c, (char *) buffer)) + if (get_user(c, (char __user *) buffer)) return -EFAULT; if (!isspace(c)) break; left--; - ((char *) buffer)++; + buffer++; } if (!left) break; @@ -1152,7 +1153,7 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write, len = left; if (len > TMPBUFLEN-1) len = TMPBUFLEN-1; - if(copy_from_user(buf, buffer, len)) + if (copy_from_user(buf, buffer, len)) return -EFAULT; buf[len] = 0; p = buf; @@ -1232,7 +1233,7 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write, * Returns 0 on success. */ int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l); } @@ -1256,7 +1257,7 @@ int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, */ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, HZ, 1000l); @@ -1279,7 +1280,7 @@ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, * Returns 0 on success. */ int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET); } @@ -1345,8 +1346,8 @@ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, /* The generic string strategy routine: */ int sysctl_string(ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) { size_t l, len; @@ -1453,7 +1454,7 @@ int sysctl_jiffies(ctl_table *table, int *name, int nlen, #else /* CONFIG_SYSCTL */ -extern asmlinkage long sys_sysctl(struct __sysctl_args *args) +extern asmlinkage long sys_sysctl(struct __sysctl_args __user *args) { return -ENOSYS; } -- cgit v1.2.3 From fd7ca8e8a929bc11254b49cdc866562233a799e7 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 10 Apr 2003 01:56:30 +0100 Subject: [AGPGART] Fold Intel i7x05 GART into intel-agp driver. Also includes various other fixes from Matt Tolentino --- drivers/char/agp/Makefile | 1 - drivers/char/agp/agp.h | 1 + drivers/char/agp/i7x05-agp.c | 240 ------------------------------------------- drivers/char/agp/intel-agp.c | 68 ++++++++++++ include/linux/agp_backend.h | 2 +- 5 files changed, 70 insertions(+), 242 deletions(-) delete mode 100644 drivers/char/agp/i7x05-agp.c (limited to 'include/linux') diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 6ad2d3d4a911..150bc6c6bdd1 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -19,5 +19,4 @@ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o obj-$(CONFIG_AGP_AMD_8151) += amd-k8-agp.o obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o -obj-$(CONFIG_AGP_I7x05) += i7x05-agp.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index fe79f0ddcd71..f38f5c7fc559 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -281,6 +281,7 @@ struct agp_bridge_data { #define INTEL_I7505_ATTBASE 0x78 #define INTEL_I7505_ERRSTS 0x42 #define INTEL_I7505_AGPCTRL 0x70 +#define INTEL_I7505_MCHCFG 0x50 /* VIA register */ #define VIA_APBASE 0x10 diff --git a/drivers/char/agp/i7x05-agp.c b/drivers/char/agp/i7x05-agp.c deleted file mode 100644 index 141d06955cdb..000000000000 --- a/drivers/char/agp/i7x05-agp.c +++ /dev/null @@ -1,240 +0,0 @@ -#include -#include -#include -#include -#include "agp.h" - -static int intel_7505_fetch_size(void) -{ - int i; - u16 tmp; - struct aper_size_info_16 *values; - - /* - * For AGP 3.0 APSIZE is now 16 bits - */ - pci_read_config_word (agp_bridge->dev, INTEL_I7505_APSIZE, &tmp); - tmp = (tmp & 0xfff); - - values = A_SIZE_16(agp_bridge->aperture_sizes); - - for (i=0; i < agp_bridge->num_aperture_sizes; i++) { - if (tmp == values[i].size_value) { - agp_bridge->previous_size = agp_bridge->current_size = - (void *)(values + i); - agp_bridge->aperture_size_idx = i; - return values[i].size; - } - } - return 0; -} - - -static void intel_7505_tlbflush(agp_memory *mem) -{ - u32 temp; - pci_read_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, &temp); - pci_write_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, temp & ~(1 << 7)); - pci_read_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, &temp); - pci_write_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, temp | (1 << 7)); -} - -static void intel_7505_cleanup(void) -{ - struct aper_size_info_16 *previous_size; - - previous_size = A_SIZE_16(agp_bridge->previous_size); - pci_write_config_byte(agp_bridge->dev, INTEL_I7505_APSIZE, - previous_size->size_value); -} - - -static int intel_7505_configure(void) -{ - u32 temp; - struct aper_size_info_16 *current_size; - - current_size = A_SIZE_16(agp_bridge->current_size); - - /* aperture size */ - pci_write_config_word(agp_bridge->dev, INTEL_I7505_APSIZE, - current_size->size_value); - - /* address to map to */ - pci_read_config_dword(agp_bridge->dev, INTEL_I7505_NAPBASELO, &temp); - agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - - /* attbase */ - pci_write_config_dword(agp_bridge->dev, INTEL_I7505_ATTBASE, - agp_bridge->gatt_bus_addr); - - /* agpctrl */ - pci_write_config_dword(agp_bridge->dev, INTEL_I7505_AGPCTRL, 0x0000); - - /* clear error registers */ - pci_write_config_byte(agp_bridge->dev, INTEL_I7505_ERRSTS, 0xff); - return 0; -} - -static struct aper_size_info_16 intel_7505_sizes[7] = -{ - {256, 65536, 6, 0xf00}, - {128, 32768, 5, 0xf20}, - {64, 16384, 4, 0xf30}, - {32, 8192, 3, 0xf38}, - {16, 4096, 2, 0xf3c}, - {8, 2048, 1, 0xf3e}, - {4, 1024, 0, 0xf3f} -}; - -static unsigned long i7x05_mask_memory(unsigned long addr, int type) -{ - /* Memory type is ignored */ - return addr | agp_bridge->masks[0].mask; -} - -static struct gatt_mask i7x05_generic_masks[] = -{ - {.mask = 0x00000017, .type = 0} -}; - - -static int __init intel_7505_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = i7x05_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_7505_sizes; - agp_bridge->size_type = U16_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_7505_configure; - agp_bridge->fetch_size = intel_7505_fetch_size; - agp_bridge->cleanup = intel_7505_cleanup; - agp_bridge->tlb_flush = intel_7505_tlbflush; - agp_bridge->mask_memory = i7x05_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} - -struct agp_device_ids i7x05_agp_device_ids[] __initdata = -{ - { - .device_id = PCI_DEVICE_ID_INTEL_7505_0, - .chipset = INTEL_I7505, - .chipset_name = "i7505", - }, - { - .device_id = PCI_DEVICE_ID_INTEL_7205_0, - .chipset = INTEL_I7505, - .chipset_name = "i7205", - }, - { }, /* dummy final entry, always present */ -}; - -/* scan table above for supported devices */ -static int __init agp_lookup_host_bridge (struct pci_dev *pdev) -{ - int j=0; - struct agp_device_ids *devs; - - devs = i7x05_agp_device_ids; - - while (devs[j].chipset_name != NULL) { - if (pdev->device == devs[j].device_id) { - printk (KERN_INFO PFX "Detected Intel %s chipset\n", - devs[j].chipset_name); - agp_bridge->type = devs[j].chipset; - - if (devs[j].chipset_setup != NULL) - return devs[j].chipset_setup(pdev); - else - return intel_7505_setup(pdev); - } - j++; - } - - printk(KERN_ERR PFX "Unsupported Intel chipset (device id: %04x),", - pdev->device); - return -ENODEV; -} - -static struct agp_driver i7x05_agp_driver = { - .owner = THIS_MODULE, -}; - -static int __init agp_i7x05_probe (struct pci_dev *dev, const struct pci_device_id *ent) -{ - u8 cap_ptr = 0; - - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - if (cap_ptr == 0) - return -ENODEV; - - if (agp_lookup_host_bridge(dev) != -ENODEV) { - agp_bridge->dev = dev; - agp_bridge->capndx = cap_ptr; - /* Fill in the mode register */ - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode); - i7x05_agp_driver.dev = dev; - agp_register_driver(&i7x05_agp_driver); - return 0; - } - return -ENODEV; -} - - -static struct pci_device_id agp_i7x05_pci_table[] __initdata = { - { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { } -}; - -MODULE_DEVICE_TABLE(pci, agp_i7x05_pci_table); - -static struct __initdata pci_driver agp_i7x05_pci_driver = { - .name = "agpgart-i7x05", - .id_table = agp_i7x05_pci_table, - .probe = agp_i7x05_probe, -}; - -int __init agp_i7x05_init(void) -{ - int ret_val; - - ret_val = pci_module_init(&agp_i7x05_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; -} - -static void __exit agp_i7x05_cleanup(void) -{ - agp_unregister_driver(&i7x05_agp_driver); - pci_unregister_driver(&agp_i7x05_pci_driver); -} - -module_init(agp_i7x05_init); -module_exit(agp_i7x05_cleanup); - -MODULE_AUTHOR("Matthew E Tolentino "); -MODULE_LICENSE("GPL and additional rights"); - diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 8a1e22c0954e..0151a80c2364 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -960,6 +960,34 @@ static int intel_830mp_configure(void) return 0; } +static int intel_7505_configure(void) +{ + u32 temp; + u16 temp2; + struct aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge->current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge->dev, INTEL_APBASE, &temp); + agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); + + /* mchcfg */ + pci_read_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, &temp2); + pci_write_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, temp2 | (1 << 9)); + + return 0; +} + static unsigned long intel_mask_memory(unsigned long addr, int type) { /* Memory type is ignored */ @@ -1246,6 +1274,34 @@ static int __init intel_860_setup (struct pci_dev *pdev) return 0; } +static int __init intel_7505_setup (struct pci_dev *pdev) +{ + agp_bridge->masks = intel_generic_masks; + agp_bridge->aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge->size_type = U8_APER_SIZE; + agp_bridge->num_aperture_sizes = 7; + agp_bridge->dev_private_data = NULL; + agp_bridge->needs_scratch_page = FALSE; + agp_bridge->configure = intel_7505_configure; + agp_bridge->fetch_size = intel_8xx_fetch_size; + agp_bridge->cleanup = intel_8xx_cleanup; + agp_bridge->tlb_flush = intel_8xx_tlbflush; + agp_bridge->mask_memory = intel_mask_memory; + agp_bridge->agp_enable = agp_generic_enable; + agp_bridge->cache_flush = global_cache_flush; + agp_bridge->create_gatt_table = agp_generic_create_gatt_table; + agp_bridge->free_gatt_table = agp_generic_free_gatt_table; + agp_bridge->insert_memory = agp_generic_insert_memory; + agp_bridge->remove_memory = agp_generic_remove_memory; + agp_bridge->alloc_by_type = agp_generic_alloc_by_type; + agp_bridge->free_by_type = agp_generic_free_by_type; + agp_bridge->agp_alloc_page = agp_generic_alloc_page; + agp_bridge->agp_destroy_page = agp_generic_destroy_page; + agp_bridge->suspend = agp_generic_suspend; + agp_bridge->resume = agp_generic_resume; + agp_bridge->cant_use_aperture = 0; + return 0; +} struct agp_device_ids intel_agp_device_ids[] __initdata = { { @@ -1329,6 +1385,18 @@ struct agp_device_ids intel_agp_device_ids[] __initdata = .chipset_name = "865G", .chipset_setup = intel_845_setup }, + { + .device_id = PCI_DEVICE_ID_INTEL_7505_0, + .chipset = INTEL_E7505, + .chipset_name = "E7505", + .chipset_setup = intel_7505_setup + }, + { + .device_id = PCI_DEVICE_ID_INTEL_7205_0, + .chipset = INTEL_E7505, + .chipset_name = "E7205", + .chipset_setup = intel_7505_setup + }, { }, /* dummy final entry, always present */ }; diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h index 4ef3f220c8bc..5bb80a3731ad 100644 --- a/include/linux/agp_backend.h +++ b/include/linux/agp_backend.h @@ -53,7 +53,7 @@ enum chipset_type { INTEL_I850, INTEL_I860, INTEL_460GX, - INTEL_I7505, + INTEL_E7505, VIA_GENERIC, SIS_GENERIC, AMD_GENERIC, -- cgit v1.2.3 From 25cd22cae57f570e7db933cd226ca09d395f0561 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 9 Apr 2003 08:13:14 -0700 Subject: Annotate fs/stat.c with user pointer annotations. --- fs/stat.c | 30 +++++++++++++++--------------- include/linux/fs.h | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/fs/stat.c b/fs/stat.c index 113f7d0c2bc0..66ed3db3061f 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -56,7 +56,7 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) return 0; } -int vfs_stat(char *name, struct kstat *stat) +int vfs_stat(char __user *name, struct kstat *stat) { struct nameidata nd; int error; @@ -69,7 +69,7 @@ int vfs_stat(char *name, struct kstat *stat) return error; } -int vfs_lstat(char *name, struct kstat *stat) +int vfs_lstat(char __user *name, struct kstat *stat) { struct nameidata nd; int error; @@ -102,7 +102,7 @@ int vfs_fstat(unsigned int fd, struct kstat *stat) * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ -static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat * statbuf) +static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * statbuf) { static int warncount = 5; struct __old_kernel_stat tmp; @@ -134,7 +134,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat * statbuf) return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; } -asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf) +asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) { struct kstat stat; int error = vfs_stat(filename, &stat); @@ -144,7 +144,7 @@ asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf) return error; } -asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf) +asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) { struct kstat stat; int error = vfs_lstat(filename, &stat); @@ -154,7 +154,7 @@ asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf) return error; } -asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf) +asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat __user * statbuf) { struct kstat stat; int error = vfs_fstat(fd, &stat); @@ -167,7 +167,7 @@ asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf) #endif -static int cp_new_stat(struct kstat *stat, struct stat *statbuf) +static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) { struct stat tmp; @@ -197,7 +197,7 @@ static int cp_new_stat(struct kstat *stat, struct stat *statbuf) return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; } -asmlinkage long sys_newstat(char * filename, struct stat * statbuf) +asmlinkage long sys_newstat(char __user * filename, struct stat __user * statbuf) { struct kstat stat; int error = vfs_stat(filename, &stat); @@ -207,7 +207,7 @@ asmlinkage long sys_newstat(char * filename, struct stat * statbuf) return error; } -asmlinkage long sys_newlstat(char * filename, struct stat * statbuf) +asmlinkage long sys_newlstat(char __user * filename, struct stat __user * statbuf) { struct kstat stat; int error = vfs_lstat(filename, &stat); @@ -217,7 +217,7 @@ asmlinkage long sys_newlstat(char * filename, struct stat * statbuf) return error; } -asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf) +asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf) { struct kstat stat; int error = vfs_fstat(fd, &stat); @@ -228,7 +228,7 @@ asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf) return error; } -asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz) +asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bufsiz) { struct nameidata nd; int error; @@ -257,7 +257,7 @@ asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz) /* ---------- LFS-64 ----------- */ #if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(__x86_64__) && !defined(CONFIG_ARCH_S390X) -static long cp_new_stat64(struct kstat *stat, struct stat64 *statbuf) +static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) { struct stat64 tmp; @@ -284,7 +284,7 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 *statbuf) return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; } -asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags) +asmlinkage long sys_stat64(char __user * filename, struct stat64 __user * statbuf, long flags) { struct kstat stat; int error = vfs_stat(filename, &stat); @@ -294,7 +294,7 @@ asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags) return error; } -asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags) +asmlinkage long sys_lstat64(char __user * filename, struct stat64 __user * statbuf, long flags) { struct kstat stat; int error = vfs_lstat(filename, &stat); @@ -304,7 +304,7 @@ asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags return error; } -asmlinkage long sys_fstat64(unsigned long fd, struct stat64 * statbuf, long flags) +asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf, long flags) { struct kstat stat; int error = vfs_fstat(fd, &stat); diff --git a/include/linux/fs.h b/include/linux/fs.h index 16ad733f58e4..223f7ebd6b80 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -738,7 +738,7 @@ struct inode_operations { int (*mknod) (struct inode *,struct dentry *,int,dev_t); int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); - int (*readlink) (struct dentry *, char *,int); + int (*readlink) (struct dentry *, char __user *,int); int (*follow_link) (struct dentry *, struct nameidata *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int); -- cgit v1.2.3 From 5edf8b9a4208987e60e0f41aff0bcc298641c0ad Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 9 Apr 2003 08:21:53 -0700 Subject: Annotate read/write paths with user pointer annotations --- fs/read_write.c | 36 ++++++++++++++++++------------------ include/linux/fs.h | 8 ++++---- 2 files changed, 22 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/fs/read_write.c b/fs/read_write.c index 04904f7fa206..7e73a7603924 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -135,7 +135,7 @@ bad: #if !defined(__alpha__) asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, - unsigned long offset_low, loff_t * result, + unsigned long offset_low, loff_t __user * result, unsigned int origin) { int retval; @@ -167,7 +167,7 @@ bad: } #endif -ssize_t do_sync_read(struct file *filp, char *buf, size_t len, loff_t *ppos) +ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { struct kiocb kiocb; ssize_t ret; @@ -181,7 +181,7 @@ ssize_t do_sync_read(struct file *filp, char *buf, size_t len, loff_t *ppos) return ret; } -ssize_t vfs_read(struct file *file, char *buf, size_t count, loff_t *pos) +ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct inode *inode = file->f_dentry->d_inode; ssize_t ret; @@ -207,7 +207,7 @@ ssize_t vfs_read(struct file *file, char *buf, size_t count, loff_t *pos) return ret; } -ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, loff_t *ppos) +ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { struct kiocb kiocb; ssize_t ret; @@ -221,7 +221,7 @@ ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, loff_t *pp return ret; } -ssize_t vfs_write(struct file *file, const char *buf, size_t count, loff_t *pos) +ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct inode *inode = file->f_dentry->d_inode; ssize_t ret; @@ -247,7 +247,7 @@ ssize_t vfs_write(struct file *file, const char *buf, size_t count, loff_t *pos) return ret; } -asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count) +asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) { struct file *file; ssize_t ret = -EBADF; @@ -261,7 +261,7 @@ asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count) return ret; } -asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count) +asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count) { struct file *file; ssize_t ret = -EBADF; @@ -275,7 +275,7 @@ asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count) return ret; } -asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf, +asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf, size_t count, loff_t pos) { struct file *file; @@ -293,7 +293,7 @@ asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf, return ret; } -asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf, +asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf, size_t count, loff_t pos) { struct file *file; @@ -332,7 +332,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) } static ssize_t do_readv_writev(int type, struct file *file, - const struct iovec * vector, + const struct iovec __user * uvector, unsigned long nr_segs, loff_t *pos) { typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *); @@ -340,7 +340,7 @@ static ssize_t do_readv_writev(int type, struct file *file, size_t tot_len; struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov=iovstack; + struct iovec *iov=iovstack, *vector; ssize_t ret; int seg; io_fn_t fn; @@ -372,7 +372,7 @@ static ssize_t do_readv_writev(int type, struct file *file, goto out; } ret = -EFAULT; - if (copy_from_user(iov, vector, nr_segs*sizeof(*vector))) + if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) goto out; /* @@ -451,7 +451,7 @@ out: return ret; } -ssize_t vfs_readv(struct file *file, const struct iovec *vec, +ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, unsigned long vlen, loff_t *pos) { if (!(file->f_mode & FMODE_READ)) @@ -462,7 +462,7 @@ ssize_t vfs_readv(struct file *file, const struct iovec *vec, return do_readv_writev(READ, file, vec, vlen, pos); } -ssize_t vfs_writev(struct file *file, const struct iovec *vec, +ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, unsigned long vlen, loff_t *pos) { if (!(file->f_mode & FMODE_WRITE)) @@ -475,7 +475,7 @@ ssize_t vfs_writev(struct file *file, const struct iovec *vec, asmlinkage ssize_t -sys_readv(unsigned long fd, const struct iovec *vec, unsigned long vlen) +sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) { struct file *file; ssize_t ret = -EBADF; @@ -490,7 +490,7 @@ sys_readv(unsigned long fd, const struct iovec *vec, unsigned long vlen) } asmlinkage ssize_t -sys_writev(unsigned long fd, const struct iovec *vec, unsigned long vlen) +sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) { struct file *file; ssize_t ret = -EBADF; @@ -586,7 +586,7 @@ out: return retval; } -asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) +asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count) { loff_t pos; off_t off; @@ -605,7 +605,7 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou return do_sendfile(out_fd, in_fd, NULL, count, MAX_NON_LFS); } -asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count) +asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count) { loff_t pos; ssize_t ret; diff --git a/include/linux/fs.h b/include/linux/fs.h index 223f7ebd6b80..5af89265c804 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -705,10 +705,10 @@ typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, u struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); - ssize_t (*read) (struct file *, char *, size_t, loff_t *); - ssize_t (*aio_read) (struct kiocb *, char *, size_t, loff_t); - ssize_t (*write) (struct file *, const char *, size_t, loff_t *); - ssize_t (*aio_write) (struct kiocb *, const char *, size_t, loff_t); + ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); + ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); + ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); + ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); -- cgit v1.2.3