L: linux-hams@vger.kernel.org
S: Maintained
+YMFPCI YAMAHA PCI SOUND
+P: Pete Zaitcev
+M: zaitcev@yahoo.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
Z85230 SYNCHRONOUS DRIVER
P: Alan Cox
M: alan@redhat.com
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 13
-EXTRAVERSION =-pre6
+EXTRAVERSION =
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
atomic_t started;
atomic_t finished;
int wait;
-} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+};
static struct call_data_struct * call_data;
-static struct call_data_struct call_data_array[NR_CPUS];
/*
* this function sends a 'generic call function' IPI to all other CPUs
* hardware interrupt handler, you may call it from a bottom half handler.
*/
{
- struct call_data_struct *data;
- int cpus = (cpu_online_map & ~(1 << smp_processor_id()));
+ struct call_data_struct data;
+ int cpus = smp_num_cpus-1;
if (!cpus)
return 0;
- data = &call_data_array[smp_processor_id()];
-
- data->func = func;
- data->info = info;
- data->wait = wait;
+ data.func = func;
+ data.info = info;
+ atomic_set(&data.started, 0);
+ data.wait = wait;
if (wait)
- atomic_set(&data->finished, 0);
- /* We have do to this one last to make sure that the IPI service
- * code desn't get confused if it gets an unexpected repeat
- * trigger of an old IPI while we're still setting up the new
- * one. */
- atomic_set(&data->started, 0);
-
- local_bh_disable();
- spin_lock(&call_lock);
- call_data = data;
+ atomic_set(&data.finished, 0);
+
+ spin_lock_bh(&call_lock);
+ call_data = &data;
+ wmb();
/* Send a message to all other CPUs and wait for them to respond */
send_IPI_allbutself(CALL_FUNCTION_VECTOR);
/* Wait for response */
- while (atomic_read(&data->started) != cpus)
+ while (atomic_read(&data.started) != cpus)
barrier();
- /* It is now safe to reuse the "call_data" global, but we need
- * to keep local bottom-halves disabled until after waiters have
- * been acknowledged to prevent reuse of the per-cpu call data
- * entry. */
- spin_unlock(&call_lock);
-
if (wait)
- while (atomic_read(&data->finished) != cpus)
+ while (atomic_read(&data.finished) != cpus)
barrier();
- local_bh_enable();
+ spin_unlock_bh(&call_lock);
return 0;
}
ack_APIC_irq();
/*
- * Notify initiating CPU that I've grabbed the data and am about
- * to execute the function (and avoid servicing any single IPI
- * twice)
+ * Notify initiating CPU that I've grabbed the data and am
+ * about to execute the function
*/
- if (test_and_set_bit(smp_processor_id(), &call_data->started))
- return;
+ mb();
+ atomic_inc(&call_data->started);
/*
* At this point the info structure may be out of scope unless wait==1
*/
(*func)(info);
- if (wait)
- set_bit(smp_processor_id(), &call_data->finished);
+ if (wait) {
+ mb();
+ atomic_inc(&call_data->finished);
+ }
}
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/stat.h>
+#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/file.h>
#include <linux/ioctl.h>
#include <linux/blkpg.h>
#include <linux/slab.h>
#include <linux/hdreg.h>
+#include <linux/spinlock.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
//#define DRIVERDEBUG
#ifdef DRIVERDEBUG
-#define DEBUG( s )
+#define DEBUG( s ) printk( s )
#else
-#define DEBUG( s ) printk( s )
+#define DEBUG( s )
#endif
/*
u32 *m = (u32 *)msg;
u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */
struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)];
-
+
+ /*
+ * Pull the lock over ready
+ */
+
+ spin_lock_prefetch(&io_request_lock);
+
/*
* FAILed message
*/
dev = &i2ob_dev[minor];
switch (cmd) {
case BLKGETSIZE:
- return put_user(i2ob[minor].nr_sects, (unsigned long *) arg);
+ return put_user(i2ob[minor].nr_sects, (long *) arg);
case BLKGETSIZE64:
return put_user((u64)i2ob[minor].nr_sects << 9, (u64 *)arg);
if(!dev->i2odev)
return 0;
+ /* Sync the device so we don't get errors */
+ fsync_dev(inode->i_rdev);
+
if (dev->refcnt <= 0)
printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
dev->refcnt--;
}
spin_unlock_irqrestore(&io_request_lock, flags);
- /*
- * Sync the device...this will force all outstanding I/Os
- * to attempt to complete, thus causing error messages.
- * We have to do this as the user could immediatelly create
- * a new volume that gets assigned the same minor number.
- * If there are still outstanding writes to the device,
- * that could cause data corruption on the new volume!
- *
- * The truth is that deleting a volume that you are currently
- * accessing will do _bad things_ to your system. This
- * handler will keep it from crashing, but must probably
- * you'll have to do a 'reboot' to get the system running
- * properly. Deleting disks you are using is dumb.
- * Umount them first and all will be good!
- *
- * It's not this driver's job to protect the system from
- * dumb user mistakes :)
- */
- if(i2ob_dev[unit].refcnt)
- fsync_dev(MKDEV(MAJOR_NR,unit));
-
/*
* Decrease usage count for module
*/
+
while(i2ob_dev[unit].refcnt--)
MOD_DEC_USE_COUNT;
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("Red Hat Software");
MODULE_DESCRIPTION("I2O Block Device OSM");
+MODULE_LICENSE("GPL");
+
void cleanup_module(void)
{
- struct gendisk *gdp;
int i;
if(evt_running) {
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("Red Hat Software");
MODULE_DESCRIPTION("I2O Configuration");
+MODULE_LICENSE("GPL");
#endif
/* Release the preserved msg by resubmitting it as a NOP */
- preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
- preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0;
+ preserved_msg[0] = cpu_to_le32(THREE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ preserved_msg[1] = cpu_to_le32(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0);
preserved_msg[2] = 0;
i2o_post_message(c, msg[7]);
up(&i2o_configuration_lock);
if(c->page_frame)
+ {
+ pci_unmap_single(c->pdev, c->page_frame_map, MSG_POOL_SIZE, PCI_DMA_FROMDEVICE);
kfree(c->page_frame);
+ }
if(c->hrt)
kfree(c->hrt);
if(c->lct)
while(mv!=0xFFFFFFFF)
{
struct i2o_handler *i;
- m=(struct i2o_message *)bus_to_virt(mv);
+ /* Map the message from the page frame map to kernel virtual */
+ m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame);
msg=(u32*)m;
+ /*
+ * Ensure this message is seen coherently but cachably by
+ * the processor
+ */
+
+ pci_dma_sync_single(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+
+ /*
+ * Despatch it
+ */
+
i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)];
if(i && i->reply)
i->reply(i,c,m);
msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
msg[3] = 0;
- msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+ msg[4] = (0<<16) | ((iop->unit+2) ); /* Host 0 IOP ID (unit + 2) */
msg[5] = 0; /* Segment 0 */
/*
c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
if(c->page_frame==NULL) {
- printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
+ printk(KERN_ERR "%s: Outbound Q initialize failed; out of memory.\n",
c->name);
return -ENOMEM;
}
- m=virt_to_bus(c->page_frame);
+
+ c->page_frame_map = pci_map_single(c->pdev, c->page_frame, MSG_POOL_SIZE, PCI_DMA_FROMDEVICE);
+
+ if(c->page_frame_map == 0)
+ {
+ kfree(c->page_frame);
+ printk(KERN_ERR "%s: Unable to map outbound queue.\n", c->name);
+ return -ENOMEM;
+ }
+
+ m = c->page_frame_map;
/* Post frames */
MODULE_AUTHOR("Red Hat Software");
MODULE_DESCRIPTION("I2O Core");
+MODULE_LICENSE("GPL");
+
int init_module(void)
/*
- * drivers/message/i2o/i2o_lan.c
+ * drivers/i2o/i2o_lan.c
*
* I2O LAN CLASS OSM May 26th 2000
*
MODULE_AUTHOR("University of Helsinki, Department of Computer Science");
MODULE_DESCRIPTION("I2O Lan OSM");
+MODULE_LICENSE("GPL");
+
MODULE_PARM(max_buckets_out, "1-" __MODULE_STRING(I2O_LAN_MAX_BUCKETS_OUT) "i");
MODULE_PARM_DESC(max_buckets_out, "Total number of buckets to post (1-)");
printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n");
c->bus.pci.mtrr_reg1 = mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
if(c->bus.pci.mtrr_reg1< 0)
+ {
printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n");
+ mtrr_del(c->bus.pci.mtrr_reg0, c->mem_phys, size);
+ c->bus.pci.mtrr_reg0 = -1;
+ }
}
#endif
{
if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
continue;
+ if(dev->vendor == PCI_VENDOR_ID_DPT)
+ {
+ if(dev->device == 0xA501 || dev->device == 0xA511)
+ {
+ printk(KERN_INFO "i2o: Skipping Adaptec/DPT I2O raid with preferred native driver.\n");
+ continue;
+ }
+ }
if((dev->class&0xFF)>1)
{
printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n");
MODULE_AUTHOR("Red Hat Software");
MODULE_DESCRIPTION("I2O PCI Interface");
+MODULE_LICENSE("GPL");
+
#else
void __init i2o_pci_init(void)
static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
-int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len,
+int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int count,
int *eof, void *data)
{
struct i2o_controller *c = (struct i2o_controller *)data;
i2o_hrt *hrt = (i2o_hrt *)c->hrt;
u32 bus;
- int count;
- int i;
+ int len, i;
spin_lock(&i2o_proc_lock);
return len;
}
- count = hrt->num_entries;
-
- if((count * hrt->entry_len + 8) > 2048) {
+ if((hrt->num_entries * hrt->entry_len + 8) > 2048) {
printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n");
len += sprintf(buf+len,
"HRT table too big to fit in buffer.\n");
}
len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n",
- count, hrt->entry_len << 2);
+ hrt->num_entries, hrt->entry_len << 2);
- for(i = 0; i < count; i++)
+ for(i = 0; i < hrt->num_entries && len < count; i++)
{
len += sprintf(buf+len, "Entry %d:\n", i);
len += sprintf(buf+len, " Adapter ID: %0#10x\n",
void i2o_proc_dev_del(struct i2o_controller *c, struct i2o_device *d)
{
#ifdef DRIVERDEBUG
- printk(KERN_INFO, "Deleting device %d from iop%d\n",
+ printk(KERN_INFO "Deleting device %d from iop%d\n",
d->lct_data.tid, c->unit);
#endif
MODULE_AUTHOR("Deepak Saxena");
MODULE_DESCRIPTION("I2O procfs Handler");
+MODULE_LICENSE("GPL");
static void __exit i2o_proc_exit(void)
{
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
+#include <linux/prefetch.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
Scsi_Cmnd *current_command;
u32 *m = (u32 *)msg;
u8 as,ds,st;
-
+
+ spin_lock_prefetch(&io_request_lock);
+
if(m[0] & (1<<13))
{
printk("IOP fail.\n");
}
return;
}
-
+
+ prefetchw(&queue_depth);
+
/*
* Low byte is device status, next is adapter status,
host = SCpnt->host;
hostdata = (struct i2o_scsi_host *)host->hostdata;
+
+ c = hostdata->controller;
+ prefetch(c);
+ prefetchw(&queue_depth);
+
SCpnt->scsi_done = done;
if(SCpnt->target > 15)
dprintk(("Real scsi messages.\n"));
- c = hostdata->controller;
/*
* Obtain an I2O message. Right now we _have_ to obtain one
}
MODULE_AUTHOR("Red Hat Software");
+MODULE_LICENSE("GPL");
+
static Scsi_Host_Template driver_template = I2OSCSI;
{'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION,
#ifdef __i386__
PROC_INTEL, PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM,
-#elif defined __ia64__
+#elif defined(__ia64__)
PROC_INTEL, PROC_IA64,
-#elif define __sparc__
+#elif defined(__sparc__)
PROC_ULTRASPARC,
#elif defined(__alpha__)
PROC_ALPHA ,
timeout *= HZ;
if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){
if(!timeout){
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irq(&io_request_lock);
schedule();
spin_lock_irq(&io_request_lock);
} else {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irq(&io_request_lock);
schedule_timeout(timeout*HZ);
spin_lock_irq(&io_request_lock);
#if defined __i386__
adpt_i386_info(&si);
-#elif defined __ia64__
+#elif defined (__ia64__)
adpt_ia64_info(&si);
-#elif define __sparc__
+#elif defined(__sparc__)
adpt_sparc_info(&si);
-#elif defined __alpha__
+#elif defined (__alpha__)
adpt_alpha_info(&si);
#else
si.processorType = 0xff ;
* I do not believe in debug levels as I never can guess what
* part of the code is going to be problematic in the future.
* Don't forget to run your klogd with -c 8.
+ *
+ * Example (do not remove):
+ * #define YMFDBG(fmt, arg...) do{ printk(KERN_DEBUG fmt, ##arg); }while(0)
*/
-/* #define YMFDBG(fmt, arg...) do{ printk(KERN_DEBUG fmt, ##arg); }while(0) */
-#define YMFDBGW(fmt, arg...) /* */
-#define YMFDBGI(fmt, arg...) /* */
+#define YMFDBGW(fmt, arg...) /* */ /* write counts */
+#define YMFDBGI(fmt, arg...) /* */ /* interrupts */
+#define YMFDBGX(fmt, arg...) /* */ /* ioctl */
static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
int w_16;
unsigned bufsize;
unsigned long flags;
- int redzone;
+ int redzone, redfrags;
int ret;
w_16 = ymf_pcm_format_width(state->format.format) == 16;
* Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT.
*/
bufsize = PAGE_SIZE << dmabuf->buforder;
- /* lets hand out reasonable big ass buffers by default */
- dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
+ /* By default we give 4 big buffers. */
+ dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2);
if (dmabuf->ossfragshift > 3 &&
dmabuf->ossfragshift < dmabuf->fragshift) {
+ /* If OSS set smaller fragments, give more smaller buffers. */
dmabuf->fragshift = dmabuf->ossfragshift;
}
- dmabuf->numfrag = bufsize >> dmabuf->fragshift;
- while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
- dmabuf->fragshift--;
- dmabuf->numfrag = bufsize >> dmabuf->fragshift;
- }
dmabuf->fragsize = 1 << dmabuf->fragshift;
- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
- if (dmabuf->ossmaxfrags >= 2 && dmabuf->ossmaxfrags < dmabuf->numfrag) {
- dmabuf->numfrag = dmabuf->ossmaxfrags;
- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
+ dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+ dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
+ if (dmabuf->ossmaxfrags >= 2) {
redzone = ymf_calc_lend(state->format.rate);
- redzone <<= (state->format.shift + 1);
- if (dmabuf->dmasize < redzone*3) {
- /*
- * The driver works correctly with minimum dmasize
- * of redzone*2, but it produces stoppage and clicks.
- * So, make it little larger for smoother sound.
- * XXX Make dmasize a wholy divisible by fragsize.
- */
-// printk(KERN_ERR "ymfpci: dmasize=%d < redzone=%d * 3\n",
-// dmabuf->dmasize, redzone);
- dmabuf->dmasize = redzone*3;
+ redzone <<= state->format.shift;
+ redzone *= 3;
+ redfrags = (redzone + dmabuf->fragsize-1) >> dmabuf->fragshift;
+
+ if (dmabuf->ossmaxfrags + redfrags < dmabuf->numfrag) {
+ dmabuf->numfrag = dmabuf->ossmaxfrags + redfrags;
+ dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
}
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&dmabuf->wait, &waita);
- YMFDBGW("ymf_write: dmabuf.count %d\n", dmabuf->count);
+ YMFDBGW("ymf_write: ret %d dmabuf.count %d\n", ret, dmabuf->count);
return ret;
}
case SNDCTL_DSP_SETSYNCRO:
case SOUND_PCM_WRITE_FILTER:
case SOUND_PCM_READ_FILTER:
+ YMFDBGX("ymf_ioctl: cmd 0x%x unsupported\n", cmd);
return -ENOTTY;
default:
* or perhaps they expect "universal" ioctls,
* for instance we get SNDCTL_TMR_CONTINUE here.
*/
- break;
+ YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
+ break;
}
return -ENOTTY;
}
int dummy5; /* unused */
} b_un;
unsigned int data[N_PARAM];
-} bdf_prm = {{30, 64, 64, 256, 5*HZ, 30*HZ, 60, 0, 0}};
+} bdf_prm = {{40, 0, 0, 0, 5*HZ, 30*HZ, 60, 0, 0}};
/* These are the min and max parameter values that we will allow to be assigned */
int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 1*HZ, 0, 0, 0};
int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 6000*HZ, 100, 0, 0};
-inline void unlock_buffer(struct buffer_head *bh)
+void unlock_buffer(struct buffer_head *bh)
{
clear_bit(BH_Wait_IO, &bh->b_state);
+ clear_bit(BH_launder, &bh->b_state);
clear_bit(BH_Lock, &bh->b_state);
smp_mb__after_clear_bit();
if (waitqueue_active(&bh->b_wait))
return 1;
}
-static int sync_page_buffers(struct buffer_head *bh, unsigned int gfp_mask)
+static int sync_page_buffers(struct buffer_head *head, unsigned int gfp_mask)
{
- struct buffer_head * p = bh;
- int tryagain = 1;
+ struct buffer_head * bh = head;
+ int tryagain = 0;
do {
- if (buffer_dirty(p) || buffer_locked(p)) {
- if (test_and_set_bit(BH_Wait_IO, &p->b_state)) {
- if (buffer_dirty(p)) {
- ll_rw_block(WRITE, 1, &p);
- tryagain = 0;
- } else if (buffer_locked(p)) {
- if (gfp_mask & __GFP_WAITBUF) {
- wait_on_buffer(p);
- tryagain = 1;
- } else
- tryagain = 0;
- }
- } else
- tryagain = 0;
+ if (!buffer_dirty(bh) && !buffer_locked(bh))
+ continue;
+
+ /* Don't start IO first time around.. */
+ if (!test_and_set_bit(BH_Wait_IO, &bh->b_state))
+ continue;
+
+ /* Second time through we start actively writing out.. */
+ if (test_and_set_bit(BH_Lock, &bh->b_state)) {
+ if (!test_bit(BH_launder, &bh->b_state))
+ continue;
+ wait_on_buffer(bh);
+ tryagain = 1;
+ continue;
+ }
+
+ if (!atomic_set_buffer_clean(bh)) {
+ unlock_buffer(bh);
+ continue;
}
- p = p->b_this_page;
- } while (p != bh);
+
+ __mark_buffer_clean(bh);
+ get_bh(bh);
+ set_bit(BH_launder, &bh->b_state);
+ bh->b_end_io = end_buffer_io_sync;
+ submit_bh(WRITE, bh);
+ tryagain = 0;
+ } while ((bh = bh->b_this_page) != head);
return tryagain;
}
*/
MODULE_AUTHOR("Anton Altaparmakov <aia21@cus.cam.ac.uk>");
MODULE_DESCRIPTION("Linux NTFS driver");
+MODULE_LICENSE("GPL");
#ifdef DEBUG
MODULE_PARM(ntdebug, "i");
MODULE_PARM_DESC(ntdebug, "Debug level");
BH_Mapped, /* 1 if the buffer has a disk mapping */
BH_New, /* 1 if the buffer is new and not yet written out */
BH_Async, /* 1 if the buffer is under end_buffer_io_async I/O */
- BH_Wait_IO, /* 1 if we should throttle on this buffer */
+ BH_Wait_IO, /* 1 if we should write out this buffer */
+ BH_launder, /* 1 if we should throttle on this buffer */
BH_PrivateStart,/* not a state bit, but the first bit available
* for private allocation by other entities
__wait_on_buffer(bh);
}
-extern void unlock_buffer(struct buffer_head *bh);
+extern void FASTCALL(unlock_buffer(struct buffer_head *bh));
/*
* super-block locking. Again, interrupts may only unlock
#define PG_checked 12 /* kill me in 2.5.<early>. */
#define PG_arch_1 13
#define PG_reserved 14
+#define PG_launder 15 /* written out by VM pressure.. */
/* Make it prettier to test the above... */
#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
#define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags)
#define PageChecked(page) test_bit(PG_checked, &(page)->flags)
#define SetPageChecked(page) set_bit(PG_checked, &(page)->flags)
+#define PageLaunder(page) test_bit(PG_launder, &(page)->flags)
+#define SetPageLaunder(page) set_bit(PG_launder, &(page)->flags)
extern void __set_page_dirty(struct page *);
* parallel wait_on_page).
*/
#define UnlockPage(page) do { \
+ clear_bit(PG_launder, &(page)->flags); \
smp_mb__before_clear_bit(); \
if (!test_and_clear_bit(PG_locked, &(page)->flags)) BUG(); \
smp_mb__after_clear_bit(); \
#define __GFP_IO 0x40 /* Can start low memory physical IO? */
#define __GFP_HIGHIO 0x80 /* Can start high mem physical IO? */
#define __GFP_FS 0x100 /* Can call down to low-level FS? */
-#define __GFP_WAITBUF 0x200 /* Can we wait for buffers to complete? */
#define GFP_NOHIGHIO (__GFP_HIGH | __GFP_WAIT | __GFP_IO)
#define GFP_NOIO (__GFP_HIGH | __GFP_WAIT)
-#define GFP_NOFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF)
+#define GFP_NOFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO)
#define GFP_ATOMIC (__GFP_HIGH)
-#define GFP_USER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS)
-#define GFP_HIGHUSER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS | __GFP_HIGHMEM)
-#define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS)
-#define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS)
-#define GFP_KSWAPD ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_WAITBUF | __GFP_FS)
+#define GFP_USER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_HIGHUSER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS | __GFP_HIGHMEM)
+#define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_KSWAPD ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some
platforms, used as appropriate on others */
#define SLAB_NFS GFP_NFS
#define SLAB_DMA GFP_DMA
-#define SLAB_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_HIGHIO|__GFP_WAITBUF|__GFP_FS)
+#define SLAB_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_HIGHIO|__GFP_FS)
#define SLAB_NO_GROW 0x00001000UL /* don't grow a cache */
/* flags to pass to kmem_cache_create().
extern void FASTCALL(lru_cache_del(struct page *));
extern void FASTCALL(deactivate_page(struct page *));
-extern void FASTCALL(deactivate_page_nolock(struct page *));
extern void FASTCALL(activate_page(struct page *));
-extern void FASTCALL(activate_page_nolock(struct page *));
extern void swap_setup(void);
/* linux/mm/vmscan.c */
extern wait_queue_head_t kswapd_wait;
-extern int FASTCALL(try_to_free_pages(unsigned int, unsigned int));
+extern int FASTCALL(try_to_free_pages(zone_t *, unsigned int, unsigned int));
/* linux/mm/page_io.c */
extern void rw_swap_page(int, struct page *);
}
/*
- * When we die, we re-parent all our children.
- * Try to give them to another thread in our process
- * group, and if no such member exists, give it to
+ * When we die, we re-parent all our children to
* the global child reaper process (ie "init")
*/
static inline void forget_original_parent(struct task_struct * father)
{
- struct task_struct * p, *reaper;
+ struct task_struct * p;
read_lock(&tasklist_lock);
- /* Next in our thread group */
- reaper = next_thread(father);
- if (reaper == father)
- reaper = child_reaper;
-
for_each_task(p) {
if (p->p_opptr == father) {
/* We dont want people slaying init */
p->exit_signal = SIGCHLD;
p->self_exec_id++;
- p->p_opptr = reaper;
+ p->p_opptr = child_reaper;
if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
}
}
struct list_head *tmp;
struct page *page;
-repeat_alloc:
page = alloc_page(GFP_NOHIGHIO);
if (page)
return page;
*/
wakeup_bdflush();
+repeat_alloc:
/*
* Try to allocate from the emergency pool.
*/
struct list_head *tmp;
struct buffer_head *bh;
-repeat_alloc:
bh = kmem_cache_alloc(bh_cachep, SLAB_NOHIGHIO);
if (bh)
return bh;
*/
wakeup_bdflush();
+repeat_alloc:
/*
* Try to allocate from the emergency pool.
*/
current->allocation_order = order;
current->flags |= PF_MEMALLOC | PF_FREE_PAGES;
- __freed = try_to_free_pages(gfp_mask, order);
+ __freed = try_to_free_pages(classzone, gfp_mask, order);
current->flags &= ~(PF_MEMALLOC | PF_FREE_PAGES);
{
pg_data_t *pgdat = pgdat_list;
unsigned int sum = 0;
- zonelist_t *zonelist;
- zone_t **zonep, *zone;
do {
- zonelist = pgdat->node_zonelists + (GFP_USER & GFP_ZONEMASK);
- zonep = zonelist->zones;
+ zonelist_t *zonelist = pgdat->node_zonelists + (GFP_USER & GFP_ZONEMASK);
+ zone_t **zonep = zonelist->zones;
+ zone_t *zone;
- for (zone = *zonep++; zone; zone = *zonep++)
- sum += zone->free_pages;
+ for (zone = *zonep++; zone; zone = *zonep++) {
+ unsigned long size = zone->size;
+ unsigned long high = zone->pages_high;
+ if (size > high)
+ sum += size - high;
+ }
pgdat = pgdat->node_next;
} while (pgdat);
- return sum + nr_active_pages + nr_inactive_pages;
+ return sum;
}
#if CONFIG_HIGHMEM
}
#endif
+#define K(x) ((x) << (PAGE_SHIFT-10))
+
/*
* Show free area list (used inside shift_scroll-lock stuff)
* We also calculate the percentage fragmentation. We do this by counting the
printk("Zone:%s freepages:%6lukB min:%6luKB low:%6lukB "
"high:%6lukB\n",
zone->name,
- (zone->free_pages)
- << ((PAGE_SHIFT-10)),
- zone->pages_min
- << ((PAGE_SHIFT-10)),
- zone->pages_low
- << ((PAGE_SHIFT-10)),
- zone->pages_high
- << ((PAGE_SHIFT-10)));
+ K(zone->free_pages),
+ K(zone->pages_min),
+ K(zone->pages_low),
+ K(zone->pages_high));
tmpdat = tmpdat->node_next;
}
printk("Free pages: %6dkB (%6dkB HighMem)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- nr_free_highpages() << (PAGE_SHIFT-10));
+ K(nr_free_pages()),
+ K(nr_free_highpages()));
printk("( Active: %d, inactive: %d, free: %d )\n",
nr_active_pages,
}
spin_unlock_irqrestore(&zone->lock, flags);
}
- printk("= %lukB)\n", total * (PAGE_SIZE>>10));
+ printk("= %lukB)\n", K(total));
}
#ifdef SWAP_CACHE_INFO
* called on a page which is not on any of the lists, the
* page is left alone.
*/
-void deactivate_page_nolock(struct page * page)
+static inline void deactivate_page_nolock(struct page * page)
{
if (PageActive(page)) {
del_page_from_active_list(page);
/*
* Move an inactive page to the active list.
*/
-void activate_page_nolock(struct page * page)
+static inline void activate_page_nolock(struct page * page)
{
if (PageInactive(page)) {
del_page_from_inactive_list(page);
*/
#define DEF_PRIORITY (6)
-#define page_zone_plenty(page) ((page)->zone->free_pages > (page)->zone->pages_high)
-
/*
* The swap-out function returns 1 if it successfully
* scanned all the pages it was asked to (`count').
*/
/* mm->page_table_lock is held. mmap_sem is not held */
-static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page)
+static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page, zone_t * classzone)
{
pte_t pte;
swp_entry_t entry;
/* Don't look at this pte if it's been accessed recently. */
if (ptep_test_and_clear_young(page_table)) {
flush_tlb_page(vma, address);
+ mark_page_accessed(page);
return 0;
}
- /* Don't bother replenishing zones that have tons of memory */
- if (page_zone_plenty(page))
+ /* Don't bother unmapping pages that are active */
+ if (PageActive(page))
+ return 0;
+
+ /* Don't bother replenishing zones not under pressure.. */
+ if (!memclass(page->zone, classzone))
return 0;
if (TryLockPage(page))
}
/* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count)
+static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone)
{
pte_t * pte;
unsigned long pmd_end;
struct page *page = pte_page(*pte);
if (VALID_PAGE(page) && !PageReserved(page)) {
- count -= try_to_swap_out(mm, vma, address, pte, page);
+ count -= try_to_swap_out(mm, vma, address, pte, page, classzone);
if (!count) {
address += PAGE_SIZE;
break;
}
/* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count)
+static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone)
{
pmd_t * pmd;
unsigned long pgd_end;
end = pgd_end;
do {
- count = swap_out_pmd(mm, vma, pmd, address, end, count);
+ count = swap_out_pmd(mm, vma, pmd, address, end, count, classzone);
if (!count)
break;
address = (address + PMD_SIZE) & PMD_MASK;
}
/* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count)
+static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count, zone_t * classzone)
{
pgd_t *pgdir;
unsigned long end;
if (address >= end)
BUG();
do {
- count = swap_out_pgd(mm, vma, pgdir, address, end, count);
+ count = swap_out_pgd(mm, vma, pgdir, address, end, count, classzone);
if (!count)
break;
address = (address + PGDIR_SIZE) & PGDIR_MASK;
/*
* Returns remaining count of pages to be swapped out by followup call.
*/
-static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter)
+static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter, zone_t * classzone)
{
unsigned long address;
struct vm_area_struct* vma;
address = vma->vm_start;
for (;;) {
- count = swap_out_vma(mm, vma, address, count);
+ count = swap_out_vma(mm, vma, address, count, classzone);
vma = vma->vm_next;
if (!vma)
break;
return count;
}
-static int FASTCALL(swap_out(unsigned int priority, unsigned int gfp_mask, int nr_pages));
-static int swap_out(unsigned int priority, unsigned int gfp_mask, int nr_pages)
+static int FASTCALL(swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * classzone));
+static int swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * classzone)
{
- int counter;
+ int counter, nr_pages = SWAP_CLUSTER_MAX;
struct mm_struct *mm;
/* Then, look at the other mm's */
atomic_inc(&mm->mm_users);
spin_unlock(&mmlist_lock);
- nr_pages = swap_out_mm(mm, nr_pages, &counter);
+ nr_pages = swap_out_mm(mm, nr_pages, &counter, classzone);
mmput(mm);
return 0;
}
-static int FASTCALL(shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask));
-static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
+static int FASTCALL(shrink_cache(int nr_pages, int max_mapped, zone_t * classzone, unsigned int gfp_mask));
+static int shrink_cache(int nr_pages, int max_mapped, zone_t * classzone, unsigned int gfp_mask)
{
struct list_head * entry;
spin_lock(&pagemap_lru_lock);
- while (max_scan && (entry = inactive_list.prev) != &inactive_list) {
+ while (max_mapped && (entry = inactive_list.prev) != &inactive_list) {
struct page * page;
if (unlikely(current->need_resched)) {
list_del(entry);
list_add(entry, &inactive_list);
- if (PageTestandClearReferenced(page))
- continue;
- max_scan--;
- if (unlikely(page_zone_plenty(page)))
+ if (!memclass(page->zone, classzone))
continue;
/* Racy check to avoid trylocking when not worthwhile */
if (!page->buffers && page_count(page) != 1)
- continue;
+ goto page_mapped;
/*
* The page is locked. IO in progress?
* Move it to the back of the list.
*/
- if (unlikely(TryLockPage(page)))
+ if (unlikely(TryLockPage(page))) {
+ if (PageLaunder(page) && (gfp_mask & __GFP_FS)) {
+ page_cache_get(page);
+ spin_unlock(&pagemap_lru_lock);
+ wait_on_page(page);
+ page_cache_release(page);
+ spin_lock(&pagemap_lru_lock);
+ }
continue;
+ }
if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) {
/*
writepage = page->mapping->a_ops->writepage;
if ((gfp_mask & __GFP_FS) && writepage) {
ClearPageDirty(page);
+ SetPageLaunder(page);
page_cache_get(page);
spin_unlock(&pagemap_lru_lock);
if (!is_page_cache_freeable(page) || PageDirty(page)) {
spin_unlock(&pagecache_lock);
UnlockPage(page);
- continue;
+page_mapped:
+ if (--max_mapped)
+ continue;
+ break;
}
/* point of no return */
spin_unlock(&pagemap_lru_lock);
}
-static int FASTCALL(shrink_caches(int priority, unsigned int gfp_mask, int nr_pages));
-static int shrink_caches(int priority, unsigned int gfp_mask, int nr_pages)
+static int FASTCALL(shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages));
+static int shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages)
{
int max_scan;
int chunk_size = nr_pages;
refill_inactive(ratio);
max_scan = nr_inactive_pages / priority;
- nr_pages = shrink_cache(nr_pages, max_scan, gfp_mask);
+ nr_pages = shrink_cache(nr_pages, max_scan, classzone, gfp_mask);
if (nr_pages <= 0)
return 0;
return nr_pages;
}
-int try_to_free_pages(unsigned int gfp_mask, unsigned int order)
+int try_to_free_pages(zone_t *classzone, unsigned int gfp_mask, unsigned int order)
{
int ret = 0;
int priority = DEF_PRIORITY;
int nr_pages = SWAP_CLUSTER_MAX;
do {
- nr_pages = shrink_caches(priority, gfp_mask, nr_pages);
+ nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages);
if (nr_pages <= 0)
return 1;
- ret |= swap_out(priority, gfp_mask, SWAP_CLUSTER_MAX << 2);
+ ret |= swap_out(priority, gfp_mask, classzone);
} while (--priority);
return ret;
schedule();
if (!zone->need_balance)
continue;
- if (!try_to_free_pages(GFP_KSWAPD, 0)) {
+ if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
zone->need_balance = 0;
__set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);