Commit 8e3ef35e authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.5

into home.osdl.org:/home/torvalds/v2.5/linux
parents f8012106 6d338bb2
...@@ -1300,7 +1300,6 @@ void __init print_IO_APIC(void) ...@@ -1300,7 +1300,6 @@ void __init print_IO_APIC(void)
reg_03.raw = io_apic_read(apic, 3); reg_03.raw = io_apic_read(apic, 3);
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
printk("\n");
printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
......
...@@ -82,7 +82,7 @@ void die_if_kernel(char *str, struct pt_regs *fp, int nr) ...@@ -82,7 +82,7 @@ void die_if_kernel(char *str, struct pt_regs *fp, int nr)
printk("Process %s (pid: %d, stackpage=%08lx)\n", printk("Process %s (pid: %d, stackpage=%08lx)\n",
current->comm, current->pid, PAGE_SIZE+(unsigned long)current); current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
show_stack((unsigned long *)fp); show_stack(NULL, (unsigned long *)fp);
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
...@@ -106,7 +106,7 @@ asmlinkage void buserr_c(struct frame *fp) ...@@ -106,7 +106,7 @@ asmlinkage void buserr_c(struct frame *fp)
int kstack_depth_to_print = 48; int kstack_depth_to_print = 48;
void show_stack(unsigned long *esp) void show_stack(struct task_struct *task, unsigned long *esp)
{ {
unsigned long *stack, *endstack, addr; unsigned long *stack, *endstack, addr;
extern char _start, _etext; extern char _start, _etext;
......
...@@ -96,6 +96,7 @@ _start: ...@@ -96,6 +96,7 @@ _start:
movec %d0, %CACR /* Enable cache */ movec %d0, %CACR /* Enable cache */
#ifdef CONFIG_ROMFS_FS
/* /*
* Move ROM filesystem above bss :-) * Move ROM filesystem above bss :-)
*/ */
...@@ -117,6 +118,12 @@ _copy_romfs: ...@@ -117,6 +118,12 @@ _copy_romfs:
cmp.l %a0, %a2 /* Check if at end */ cmp.l %a0, %a2 /* Check if at end */
bne _copy_romfs bne _copy_romfs
#else /* CONFIG_ROMFS_FS */
lea.l _ebss, %a1
move.l %a1, _ramstart
#endif /* CONFIG_ROMFS_FS */
/* /*
* Zero out the bss region. * Zero out the bss region.
*/ */
......
...@@ -116,6 +116,8 @@ _start: ...@@ -116,6 +116,8 @@ _start:
movec %d0, %CACR /* Enable cache */ movec %d0, %CACR /* Enable cache */
nop nop
#ifdef CONFIG_ROMFS_FS
#ifdef CONFIG_ROMFS_FROM_ROM #ifdef CONFIG_ROMFS_FROM_ROM
/* /*
* check for an in RAM romfs * check for an in RAM romfs
...@@ -160,6 +162,12 @@ _copy_romfs: ...@@ -160,6 +162,12 @@ _copy_romfs:
done_romfs: done_romfs:
#endif #endif
#else /* CONFIG_ROMFS_FS */
lea.l _ebss, %a1
move.l %a1, _ramstart
#endif /* CONFIG_ROMFS_FS */
/* /*
* Zero out the bss region. * Zero out the bss region.
*/ */
......
...@@ -1337,7 +1337,7 @@ static void bh_lru_install(struct buffer_head *bh) ...@@ -1337,7 +1337,7 @@ static void bh_lru_install(struct buffer_head *bh)
check_irqs_on(); check_irqs_on();
bh_lru_lock(); bh_lru_lock();
lru = &per_cpu(bh_lrus, smp_processor_id()); lru = &__get_cpu_var(bh_lrus);
if (lru->bhs[0] != bh) { if (lru->bhs[0] != bh) {
struct buffer_head *bhs[BH_LRU_SIZE]; struct buffer_head *bhs[BH_LRU_SIZE];
int in; int in;
...@@ -1381,7 +1381,7 @@ lookup_bh_lru(struct block_device *bdev, sector_t block, int size) ...@@ -1381,7 +1381,7 @@ lookup_bh_lru(struct block_device *bdev, sector_t block, int size)
check_irqs_on(); check_irqs_on();
bh_lru_lock(); bh_lru_lock();
lru = &per_cpu(bh_lrus, smp_processor_id()); lru = &__get_cpu_var(bh_lrus);
for (i = 0; i < BH_LRU_SIZE; i++) { for (i = 0; i < BH_LRU_SIZE; i++) {
struct buffer_head *bh = lru->bhs[i]; struct buffer_head *bh = lru->bhs[i];
...@@ -1474,15 +1474,14 @@ EXPORT_SYMBOL(__bread); ...@@ -1474,15 +1474,14 @@ EXPORT_SYMBOL(__bread);
*/ */
static void invalidate_bh_lru(void *arg) static void invalidate_bh_lru(void *arg)
{ {
const int cpu = get_cpu(); struct bh_lru *b = &get_cpu_var(bh_lrus);
struct bh_lru *b = &per_cpu(bh_lrus, cpu);
int i; int i;
for (i = 0; i < BH_LRU_SIZE; i++) { for (i = 0; i < BH_LRU_SIZE; i++) {
brelse(b->bhs[i]); brelse(b->bhs[i]);
b->bhs[i] = NULL; b->bhs[i] = NULL;
} }
put_cpu(); put_cpu_var(bh_lrus);
} }
static void invalidate_bh_lrus(void) static void invalidate_bh_lrus(void)
......
...@@ -1562,6 +1562,8 @@ static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) ...@@ -1562,6 +1562,8 @@ static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_VT
static int vt_check(struct file *file) static int vt_check(struct file *file)
{ {
struct tty_struct *tty; struct tty_struct *tty;
...@@ -1693,6 +1695,8 @@ static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc3 ...@@ -1693,6 +1695,8 @@ static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc3
return 0; return 0;
} }
#endif /* CONFIG_VT */
static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
mm_segment_t old_fs = get_fs(); mm_segment_t old_fs = get_fs();
...@@ -2398,11 +2402,13 @@ HANDLE_IOCTL(LOOP_SET_STATUS, loop_status) ...@@ -2398,11 +2402,13 @@ HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
HANDLE_IOCTL(LOOP_GET_STATUS, loop_status) HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)
#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout)
#ifdef CONFIG_VT
HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl) HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl)
HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl) HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl)
HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl) HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl)
HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl) HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl)
HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl)
#endif
HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl) HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl)
HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl) HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl)
HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl) HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl)
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include <linux/sunrpc/svcsock.h> #include <linux/sunrpc/svcsock.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/nfs.h> #include <linux/nfs.h>
#include <linux/suspend.h>
#define NLMDBG_FACILITY NLMDBG_SVC #define NLMDBG_FACILITY NLMDBG_SVC
#define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE)
...@@ -122,8 +121,6 @@ lockd(struct svc_rqst *rqstp) ...@@ -122,8 +121,6 @@ lockd(struct svc_rqst *rqstp)
while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) {
long timeout = MAX_SCHEDULE_TIMEOUT; long timeout = MAX_SCHEDULE_TIMEOUT;
if (current->flags & PF_FREEZE)
refrigerator(PF_IOTHREAD);
if (signalled()) { if (signalled()) {
flush_signals(current); flush_signals(current);
if (nlmsvc_ops) { if (nlmsvc_ops) {
......
...@@ -195,8 +195,7 @@ int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -195,8 +195,7 @@ int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
static int expkey_show(struct seq_file *m, static int expkey_show(struct seq_file *m,
struct cache_detail *cd, struct cache_detail *cd,
struct cache_head *h, struct cache_head *h)
char *pbuf)
{ {
struct svc_expkey *ek ; struct svc_expkey *ek ;
...@@ -436,9 +435,8 @@ int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -436,9 +435,8 @@ int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong); static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong);
static int svc_export_show(struct seq_file *m, static int svc_export_show(struct seq_file *m,
struct cache_detail *cd, struct cache_detail *cd,
struct cache_head *h, struct cache_head *h)
char *pbuf)
{ {
struct svc_export *exp ; struct svc_export *exp ;
...@@ -1028,17 +1026,11 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t ...@@ -1028,17 +1026,11 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t
seq_printf(m, "%sanongid=%d", first++?",":"", anong); seq_printf(m, "%sanongid=%d", first++?",":"", anong);
} }
static inline void mangle(struct seq_file *m, const char *s)
{
seq_escape(m, s, " \t\n\\");
}
static int e_show(struct seq_file *m, void *p) static int e_show(struct seq_file *m, void *p)
{ {
struct cache_head *cp = p; struct cache_head *cp = p;
struct svc_export *exp = container_of(cp, struct svc_export, h); struct svc_export *exp = container_of(cp, struct svc_export, h);
svc_client *clp; svc_client *clp;
char *pbuf;
if (p == (void *)1) { if (p == (void *)1) {
seq_puts(m, "# Version 1.1\n"); seq_puts(m, "# Version 1.1\n");
...@@ -1051,17 +1043,7 @@ static int e_show(struct seq_file *m, void *p) ...@@ -1051,17 +1043,7 @@ static int e_show(struct seq_file *m, void *p)
if (cache_check(&svc_export_cache, &exp->h, NULL)) if (cache_check(&svc_export_cache, &exp->h, NULL))
return 0; return 0;
if (cache_put(&exp->h, &svc_export_cache)) BUG(); if (cache_put(&exp->h, &svc_export_cache)) BUG();
pbuf = m->private; return svc_export_show(m, &svc_export_cache, cp);
mangle(m, d_path(exp->ex_dentry, exp->ex_mnt,
pbuf, PAGE_SIZE));
seq_putc(m, '\t');
mangle(m, clp->name);
seq_putc(m, '(');
exp_flags(m, exp->ex_flags, exp->ex_fsid,
exp->ex_anon_uid, exp->ex_anon_gid);
seq_puts(m, ")\n");
return 0;
} }
struct seq_operations nfs_exports_op = { struct seq_operations nfs_exports_op = {
......
...@@ -55,12 +55,6 @@ ...@@ -55,12 +55,6 @@
#define NFSDDBG_FACILITY NFSDDBG_PROC #define NFSDDBG_FACILITY NFSDDBG_PROC
static inline int
nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
{
return nfs_ok;
}
/* Note: The organization of the OPEN code seems a little strange; it /* Note: The organization of the OPEN code seems a little strange; it
* has been superfluously split into three routines, one of which is named * has been superfluously split into three routines, one of which is named
* nfsd4_process_open2() even though there is no nfsd4_process_open1()! * nfsd4_process_open2() even though there is no nfsd4_process_open1()!
...@@ -140,10 +134,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open ...@@ -140,10 +134,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
status = nfsd4_process_open2(rqstp, current_fh, open); status = nfsd4_process_open2(rqstp, current_fh, open);
if (status) if (status)
return status; return status;
/*
* To finish the open response, we just need to set the rflags.
*/
open->op_rflags = 0;
return 0; return 0;
} }
...@@ -356,14 +346,51 @@ nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_loo ...@@ -356,14 +346,51 @@ nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_loo
static inline int static inline int
nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
{ {
struct nfs4_stateid *stp;
int status;
/* no need to check permission - this will be done in nfsd_read() */ /* no need to check permission - this will be done in nfsd_read() */
if (read->rd_offset >= OFFSET_MAX) if (read->rd_offset >= OFFSET_MAX)
return nfserr_inval; return nfserr_inval;
nfsd4_lock_state();
status = nfs_ok;
/* For stateid -1, we don't check share reservations. */
if (ONE_STATEID(&read->rd_stateid)) {
dprintk("NFSD: nfsd4_read: -1 stateid...\n");
goto out;
}
/*
* For stateid 0, the client doesn't have to have the file open, but
* we still check for share reservation conflicts.
*/
if (ZERO_STATEID(&read->rd_stateid)) {
dprintk("NFSD: nfsd4_read: zero stateid...\n");
if ((status = nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_READ))) {
dprintk("NFSD: nfsd4_read: conflicting share reservation!\n");
goto out;
}
status = nfs_ok;
goto out;
}
/* check stateid */
if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid,
CHECK_FH, &stp))) {
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out;
}
status = nfserr_openmode;
if (!(stp->st_share_access & NFS4_SHARE_ACCESS_READ)) {
dprintk("NFSD: nfsd4_read: file not opened for read!\n");
goto out;
}
status = nfs_ok;
out:
nfsd4_unlock_state();
read->rd_rqstp = rqstp; read->rd_rqstp = rqstp;
read->rd_fhp = current_fh; read->rd_fhp = current_fh;
return nfs_ok; return status;
} }
static inline int static inline int
...@@ -425,28 +452,85 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, ...@@ -425,28 +452,85 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
static inline int static inline int
nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr) nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
{ {
return nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0); struct nfs4_stateid *stp;
int status = nfs_ok;
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
status = nfserr_bad_stateid;
if (ZERO_STATEID(&setattr->sa_stateid) || ONE_STATEID(&setattr->sa_stateid)) {
dprintk("NFSD: nfsd4_setattr: magic stateid!\n");
return status;
}
nfsd4_lock_state();
if ((status = nfs4_preprocess_stateid_op(current_fh,
&setattr->sa_stateid,
CHECK_FH, &stp))) {
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
goto out;
}
status = nfserr_openmode;
if (!(stp->st_share_access & NFS4_SHARE_ACCESS_WRITE)) {
dprintk("NFSD: nfsd4_setattr: not opened for write!\n");
goto out;
}
nfsd4_unlock_state();
}
return (nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0));
out:
nfsd4_unlock_state();
return status;
} }
static inline int static inline int
nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write) nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write)
{ {
struct nfs4_stateid *stp;
stateid_t *stateid = &write->wr_stateid;
u32 *p; u32 *p;
int status = nfs_ok;
/* no need to check permission - this will be done in nfsd_write() */ /* no need to check permission - this will be done in nfsd_write() */
if (write->wr_offset >= OFFSET_MAX) if (write->wr_offset >= OFFSET_MAX)
return nfserr_inval; return nfserr_inval;
nfsd4_lock_state();
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
dprintk("NFSD: nfsd4_write: zero stateid...\n");
if ((status = nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_WRITE))) {
dprintk("NFSD: nfsd4_write: conflicting share reservation!\n");
goto out;
}
goto zero_stateid;
}
if ((status = nfs4_preprocess_stateid_op(current_fh, stateid,
CHECK_FH, &stp))) {
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
goto out;
}
status = nfserr_openmode;
if (!(stp->st_share_access & NFS4_SHARE_ACCESS_WRITE)) {
dprintk("NFSD: nfsd4_write: file not open for write!\n");
goto out;
}
zero_stateid:
nfsd4_unlock_state();
write->wr_bytes_written = write->wr_buflen; write->wr_bytes_written = write->wr_buflen;
write->wr_how_written = write->wr_stable_how; write->wr_how_written = write->wr_stable_how;
p = (u32 *)write->wr_verifier; p = (u32 *)write->wr_verifier;
*p++ = nfssvc_boot.tv_sec; *p++ = nfssvc_boot.tv_sec;
*p++ = nfssvc_boot.tv_usec; *p++ = nfssvc_boot.tv_usec;
return nfsd_write(rqstp, current_fh, write->wr_offset, return (nfsd_write(rqstp, current_fh, write->wr_offset,
write->wr_vec, write->wr_vlen, write->wr_buflen, write->wr_vec, write->wr_vlen, write->wr_buflen,
&write->wr_how_written); &write->wr_how_written));
out:
nfsd4_unlock_state();
return status;
} }
/* This routine never returns NFS_OK! If there are no other errors, it /* This routine never returns NFS_OK! If there are no other errors, it
...@@ -609,6 +693,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -609,6 +693,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
case OP_OPEN: case OP_OPEN:
op->status = nfsd4_open(rqstp, &current_fh, &op->u.open); op->status = nfsd4_open(rqstp, &current_fh, &op->u.open);
break; break;
case OP_OPEN_CONFIRM:
op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm);
break;
case OP_OPEN_DOWNGRADE:
op->status = nfsd4_open_downgrade(rqstp, &current_fh, &op->u.open_downgrade);
break;
case OP_PUTFH: case OP_PUTFH:
op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh); op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh);
break; break;
......
...@@ -56,12 +56,20 @@ static u32 current_clientid = 1; ...@@ -56,12 +56,20 @@ static u32 current_clientid = 1;
static u32 current_ownerid = 0; static u32 current_ownerid = 0;
static u32 current_fileid = 0; static u32 current_fileid = 0;
static u32 nfs4_init = 0; static u32 nfs4_init = 0;
stateid_t zerostateid; /* bits all 0 */
stateid_t onestateid; /* bits all 1 */
/* debug counters */ /* debug counters */
u32 list_add_perfile = 0; u32 list_add_perfile = 0;
u32 list_del_perfile = 0; u32 list_del_perfile = 0;
u32 add_perclient = 0; u32 add_perclient = 0;
u32 del_perclient = 0; u32 del_perclient = 0;
u32 alloc_file = 0;
u32 free_file = 0;
u32 alloc_sowner = 0;
u32 free_sowner = 0;
u32 vfsopen = 0;
u32 vfsclose = 0;
/* Locking: /* Locking:
* *
...@@ -71,6 +79,18 @@ u32 del_perclient = 0; ...@@ -71,6 +79,18 @@ u32 del_perclient = 0;
*/ */
static struct semaphore client_sema; static struct semaphore client_sema;
void
nfsd4_lock_state(void)
{
down(&client_sema);
}
void
nfsd4_unlock_state(void)
{
up(&client_sema);
}
static inline u32 static inline u32
opaque_hashval(const void *ptr, int nbytes) opaque_hashval(const void *ptr, int nbytes)
{ {
...@@ -87,6 +107,8 @@ opaque_hashval(const void *ptr, int nbytes) ...@@ -87,6 +107,8 @@ opaque_hashval(const void *ptr, int nbytes)
/* forward declarations */ /* forward declarations */
static void release_stateowner(struct nfs4_stateowner *sop); static void release_stateowner(struct nfs4_stateowner *sop);
static void release_stateid(struct nfs4_stateid *stp); static void release_stateid(struct nfs4_stateid *stp);
static void release_file(struct nfs4_file *fp);
/* /*
* SETCLIENTID state * SETCLIENTID state
...@@ -136,7 +158,8 @@ STALE_CLIENTID(clientid_t *clid) ...@@ -136,7 +158,8 @@ STALE_CLIENTID(clientid_t *clid)
{ {
if (clid->cl_boot == boot_time) if (clid->cl_boot == boot_time)
return 0; return 0;
printk("NFSD stale clientid (%08x/%08x)\n", clid->cl_boot, clid->cl_id); dprintk("NFSD stale clientid (%08x/%08x)\n",
clid->cl_boot, clid->cl_id);
return 1; return 1;
} }
...@@ -294,6 +317,7 @@ move_to_confirmed(struct nfs4_client *clp, unsigned int idhashval) ...@@ -294,6 +317,7 @@ move_to_confirmed(struct nfs4_client *clp, unsigned int idhashval)
{ {
unsigned int strhashval; unsigned int strhashval;
dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
list_del_init(&clp->cl_strhash); list_del_init(&clp->cl_strhash);
list_del_init(&clp->cl_idhash); list_del_init(&clp->cl_idhash);
list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
...@@ -646,20 +670,30 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi ...@@ -646,20 +670,30 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
#define ownerid_hashval(id) \
((id) & OWNER_HASH_MASK)
#define ownerstr_hashval(clientid, ownername) \ #define ownerstr_hashval(clientid, ownername) \
(((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK) (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
/* hash table for nfs4_file */ /* hash table for nfs4_file */
#define FILE_HASH_BITS 8 #define FILE_HASH_BITS 8
#define FILE_HASH_SIZE (1 << FILE_HASH_BITS) #define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
#define FILE_HASH_MASK (FILE_HASH_SIZE - 1) #define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
/* hash table for (open)nfs4_stateid */
#define OPENSTATEID_HASH_BITS 10
#define OPENSTATEID_HASH_SIZE (1 << OPENSTATEID_HASH_BITS)
#define OPENSTATEID_HASH_MASK (OPENSTATEID_HASH_SIZE - 1)
#define file_hashval(x) \ #define file_hashval(x) \
((unsigned int)((x)->dev + (x)->ino + (x)->generation) & FILE_HASH_MASK) ((unsigned int)((x)->dev + (x)->ino + (x)->generation) & FILE_HASH_MASK)
#define openstateid_hashval(owner_id, file_id) \
(((owner_id) + (file_id)) & OPENSTATEID_HASH_MASK)
static struct list_head file_hashtbl[FILE_HASH_SIZE]; static struct list_head file_hashtbl[FILE_HASH_SIZE];
static struct list_head openstateid_hashtbl[OPENSTATEID_HASH_SIZE];
/* OPEN Share state helper functions */ /* OPEN Share state helper functions */
static inline struct nfs4_file * static inline struct nfs4_file *
...@@ -671,6 +705,7 @@ alloc_init_file(unsigned int hashval, nfs4_ino_desc_t *ino) { ...@@ -671,6 +705,7 @@ alloc_init_file(unsigned int hashval, nfs4_ino_desc_t *ino) {
list_add(&fp->fi_hash, &file_hashtbl[hashval]); list_add(&fp->fi_hash, &file_hashtbl[hashval]);
memcpy(&fp->fi_ino, ino, sizeof(nfs4_ino_desc_t)); memcpy(&fp->fi_ino, ino, sizeof(nfs4_ino_desc_t));
fp->fi_id = current_fileid++; fp->fi_id = current_fileid++;
alloc_file++;
return fp; return fp;
} }
return (struct nfs4_file *)NULL; return (struct nfs4_file *)NULL;
...@@ -689,8 +724,7 @@ release_all_files(void) ...@@ -689,8 +724,7 @@ release_all_files(void)
if(!list_empty(&fp->fi_perfile)) { if(!list_empty(&fp->fi_perfile)) {
printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp); printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);
} }
list_del_init(&fp->fi_hash); release_file(fp);
kfree(fp);
} }
} }
} }
...@@ -718,26 +752,31 @@ free_stateowner(struct nfs4_stateowner *sop) { ...@@ -718,26 +752,31 @@ free_stateowner(struct nfs4_stateowner *sop) {
kfree(sop->so_owner.data); kfree(sop->so_owner.data);
kfree(sop); kfree(sop);
sop = NULL; sop = NULL;
free_sowner++;
} }
} }
static struct nfs4_stateowner * static struct nfs4_stateowner *
alloc_init_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { alloc_init_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
struct nfs4_stateowner *sop; struct nfs4_stateowner *sop;
unsigned int idhashval;
if (!(sop = alloc_stateowner(&open->op_owner))) if (!(sop = alloc_stateowner(&open->op_owner)))
return (struct nfs4_stateowner *)NULL; return (struct nfs4_stateowner *)NULL;
idhashval = ownerid_hashval(current_ownerid);
INIT_LIST_HEAD(&sop->so_idhash);
INIT_LIST_HEAD(&sop->so_strhash); INIT_LIST_HEAD(&sop->so_strhash);
INIT_LIST_HEAD(&sop->so_perclient); INIT_LIST_HEAD(&sop->so_perclient);
INIT_LIST_HEAD(&sop->so_peropenstate); INIT_LIST_HEAD(&sop->so_peropenstate);
list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
list_add(&sop->so_perclient, &clp->cl_perclient); list_add(&sop->so_perclient, &clp->cl_perclient);
add_perclient++; add_perclient++;
sop->so_id = current_ownerid++; sop->so_id = current_ownerid++;
sop->so_client = clp; sop->so_client = clp;
sop->so_seqid = open->op_seqid; sop->so_seqid = open->op_seqid;
/* until open_confirm is coded, pretend it happened! */ sop->so_confirmed = 0;
sop->so_confirmed = 1; alloc_sowner++;
return sop; return sop;
} }
...@@ -746,6 +785,7 @@ release_stateowner(struct nfs4_stateowner *sop) ...@@ -746,6 +785,7 @@ release_stateowner(struct nfs4_stateowner *sop)
{ {
struct nfs4_stateid *stp; struct nfs4_stateid *stp;
list_del_init(&sop->so_idhash);
list_del_init(&sop->so_strhash); list_del_init(&sop->so_strhash);
list_del_init(&sop->so_perclient); list_del_init(&sop->so_perclient);
del_perclient++; del_perclient++;
...@@ -759,9 +799,12 @@ release_stateowner(struct nfs4_stateowner *sop) ...@@ -759,9 +799,12 @@ release_stateowner(struct nfs4_stateowner *sop)
static inline void static inline void
init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open) { init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open) {
unsigned int hashval = openstateid_hashval(sop->so_id, fp->fi_id);
INIT_LIST_HEAD(&stp->st_hash);
INIT_LIST_HEAD(&stp->st_peropenstate); INIT_LIST_HEAD(&stp->st_peropenstate);
INIT_LIST_HEAD(&stp->st_perfile); INIT_LIST_HEAD(&stp->st_perfile);
list_add(&stp->st_hash, &openstateid_hashtbl[hashval]);
list_add(&stp->st_peropenstate, &sop->so_peropenstate); list_add(&stp->st_peropenstate, &sop->so_peropenstate);
list_add_perfile++; list_add_perfile++;
list_add(&stp->st_perfile, &fp->fi_perfile); list_add(&stp->st_perfile, &fp->fi_perfile);
...@@ -778,11 +821,13 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateow ...@@ -778,11 +821,13 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateow
static void static void
release_stateid(struct nfs4_stateid *stp) { release_stateid(struct nfs4_stateid *stp) {
list_del_init(&stp->st_hash);
list_del_perfile++; list_del_perfile++;
list_del_init(&stp->st_perfile); list_del_init(&stp->st_perfile);
list_del_init(&stp->st_peropenstate); list_del_init(&stp->st_peropenstate);
if(stp->st_vfs_set) { if(stp->st_vfs_set) {
nfsd_close(&stp->st_vfs_file); nfsd_close(&stp->st_vfs_file);
vfsclose++;
dput(stp->st_vfs_file.f_dentry); dput(stp->st_vfs_file.f_dentry);
mntput(stp->st_vfs_file.f_vfsmnt); mntput(stp->st_vfs_file.f_vfsmnt);
} }
...@@ -791,6 +836,37 @@ release_stateid(struct nfs4_stateid *stp) { ...@@ -791,6 +836,37 @@ release_stateid(struct nfs4_stateid *stp) {
stp = NULL; stp = NULL;
} }
static void
release_file(struct nfs4_file *fp)
{
free_file++;
list_del_init(&fp->fi_hash);
kfree(fp);
}
void
release_open_state(struct nfs4_stateid *stp)
{
struct nfs4_stateowner *sop = stp->st_stateowner;
struct nfs4_file *fp = stp->st_file;
dprintk("NFSD: release_open_state\n");
release_stateid(stp);
/*
* release unused nfs4_stateowners.
* XXX will need to be placed on an open_stateid_lru list to be
* released by the laundromat service after the lease period
* to enable us to handle CLOSE replay
*/
if (sop->so_confirmed && list_empty(&sop->so_peropenstate)) {
release_stateowner(sop);
}
/* unused nfs4_file's are releseed. XXX slab cache? */
if (list_empty(&fp->fi_perfile)) {
release_file(fp);
}
}
static int static int
cmp_owner_str(struct nfs4_stateowner *sop, struct nfsd4_open *open) { cmp_owner_str(struct nfs4_stateowner *sop, struct nfsd4_open *open) {
return ((sop->so_owner.len == open->op_owner.len) && return ((sop->so_owner.len == open->op_owner.len) &&
...@@ -872,6 +948,30 @@ nfs4_init_ino(nfs4_ino_desc_t *ino, struct svc_fh *fhp) ...@@ -872,6 +948,30 @@ nfs4_init_ino(nfs4_ino_desc_t *ino, struct svc_fh *fhp)
ino->generation = inode->i_generation; ino->generation = inode->i_generation;
} }
int
nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
nfs4_ino_desc_t ino;
unsigned int fi_hashval;
struct nfs4_file *fp;
struct nfs4_stateid *stp;
struct list_head *pos, *next;
dprintk("NFSD: nfs4_share_conflict\n");
nfs4_init_ino(&ino, current_fh);
fi_hashval = file_hashval(&ino);
if (find_file(fi_hashval, &ino, &fp)) {
/* Search for conflicting share reservations */
list_for_each_safe(pos, next, &fp->fi_perfile) {
stp = list_entry(pos, struct nfs4_stateid, st_perfile);
if (stp->st_share_deny & deny_type)
return nfserr_share_denied;
}
}
return nfs_ok;
}
static inline int static inline int
nfs4_file_upgrade(struct file *filp, unsigned int share_access) nfs4_file_upgrade(struct file *filp, unsigned int share_access)
{ {
...@@ -887,6 +987,15 @@ int status; ...@@ -887,6 +987,15 @@ int status;
return nfs_ok; return nfs_ok;
} }
static inline void
nfs4_file_downgrade(struct file *filp, unsigned int share_access)
{
if (share_access & NFS4_SHARE_ACCESS_WRITE) {
put_write_access(filp->f_dentry->d_inode);
filp->f_mode = FMODE_READ;
}
}
/* /*
* nfsd4_process_open1() * nfsd4_process_open1()
...@@ -981,7 +1090,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf ...@@ -981,7 +1090,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfs4_stateid *stq, *stp = NULL; struct nfs4_stateid *stq, *stp = NULL;
int status; int status;
status = nfserr_resource; status = nfserr_resource;
if (!sop) if (!sop)
goto out; goto out;
...@@ -1026,6 +1134,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf ...@@ -1026,6 +1134,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
&stp->st_vfs_file)) != 0) &stp->st_vfs_file)) != 0)
goto out_free; goto out_free;
vfsopen++;
dget(stp->st_vfs_file.f_dentry); dget(stp->st_vfs_file.f_dentry);
mntget(stp->st_vfs_file.f_vfsmnt); mntget(stp->st_vfs_file.f_vfsmnt);
...@@ -1063,6 +1172,13 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf ...@@ -1063,6 +1172,13 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
status = nfs_ok; status = nfs_ok;
out: out:
/*
* To finish the open response, we just need to set the rflags.
*/
open->op_rflags = 0;
if (!open->op_stateowner->so_confirmed)
open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
up(&client_sema); /*XXX need finer grained locking */ up(&client_sema); /*XXX need finer grained locking */
return status; return status;
out_free: out_free:
...@@ -1154,6 +1270,326 @@ laundromat_main(void *not_used) ...@@ -1154,6 +1270,326 @@ laundromat_main(void *not_used)
schedule_delayed_work(&laundromat_work, t*HZ); schedule_delayed_work(&laundromat_work, t*HZ);
} }
/* search openstateid_hashtbl[] for stateid */
struct nfs4_stateid *
find_stateid(stateid_t *stid)
{
struct list_head *pos, *next;
struct nfs4_stateid *local = NULL;
u32 st_id = stid->si_stateownerid;
u32 f_id = stid->si_fileid;
unsigned int hashval = openstateid_hashval(st_id, f_id);
list_for_each_safe(pos, next, &openstateid_hashtbl[hashval]) {
local = list_entry(pos, struct nfs4_stateid, st_hash);
if((local->st_stateid.si_stateownerid == st_id) &&
(local->st_stateid.si_fileid == f_id))
return local;
}
return NULL;
}
/* search ownerid_hashtbl[] for stateid owner (stateid->si_stateownerid) */
struct nfs4_stateowner *
find_stateowner_id(u32 st_id) {
struct list_head *pos, *next;
struct nfs4_stateowner *local = NULL;
unsigned int hashval = ownerid_hashval(st_id);
list_for_each_safe(pos, next, &ownerid_hashtbl[hashval]) {
local = list_entry(pos, struct nfs4_stateowner, so_idhash);
if(local->so_id == st_id)
return local;
}
return NULL;
}
static inline int
nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
{
return (fhp->fh_dentry != stp->st_vfs_file.f_dentry);
}
static int
STALE_STATEID(stateid_t *stateid)
{
if (stateid->si_boot == boot_time)
return 0;
printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
stateid->si_generation);
return 1;
}
/*
* Checks for stateid operations
*/
int
nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct nfs4_stateid **stpp)
{
struct nfs4_stateid *stp;
int status;
dprintk("NFSD: preprocess_stateid_op:stateid = (%08x/%08x/%08x/%08x)\n",
stateid->si_boot, stateid->si_stateownerid,
stateid->si_fileid, stateid->si_generation);
*stpp = NULL;
/* STALE STATEID */
status = nfserr_stale_stateid;
if (STALE_STATEID(stateid))
goto out;
/* BAD STATEID */
status = nfserr_bad_stateid;
if (!(stp = find_stateid(stateid))) {
dprintk("NFSD: process stateid: no open stateid!\n");
goto out;
}
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
goto out;
}
if (!stp->st_stateowner->so_confirmed) {
dprintk("process_stateid: lockowner not confirmed yet!\n");
goto out;
}
if (stateid->si_generation > stp->st_stateid.si_generation) {
dprintk("process_stateid: future stateid?!\n");
goto out;
}
/* OLD STATEID */
status = nfserr_old_stateid;
if (stateid->si_generation < stp->st_stateid.si_generation) {
dprintk("process_stateid: old stateid!\n");
goto out;
}
*stpp = stp;
status = nfs_ok;
renew_client(stp->st_stateowner->so_client);
out:
return status;
}
/*
* Checks for sequence id mutating operations.
*
* XXX need to code replay cache logic
*/
int
nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp)
{
int status;
struct nfs4_stateid *stp;
struct nfs4_stateowner *sop;
dprintk("NFSD: preprocess_seqid_op: seqid=%d "
"stateid = (%08x/%08x/%08x/%08x)\n", seqid,
stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
stateid->si_generation);
*stpp = NULL;
*sopp = NULL;
status = nfserr_bad_stateid;
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
printk("NFSD: preprocess_seqid_op: magic stateid!\n");
goto out;
}
status = nfserr_stale_stateid;
if (STALE_STATEID(stateid))
goto out;
/*
* We return BAD_STATEID if filehandle doesn't match stateid,
* the confirmed flag is incorrecly set, or the generation
* number is incorrect.
* If there is no entry in the openfile table for this id,
* we can't always return BAD_STATEID;
* this might be a retransmitted CLOSE which has arrived after
* the openfile has been released.
*/
if (!(stp = find_stateid(stateid)))
goto no_nfs4_stateid;
status = nfserr_bad_stateid;
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
goto out;
}
*stpp = stp;
*sopp = sop = stp->st_stateowner;
/*
* We now validate the seqid and stateid generation numbers.
* For the moment, we ignore the possibility of
* generation number wraparound.
*/
if (seqid != sop->so_seqid + 1)
goto check_replay;
if (sop->so_confirmed) {
if (flags & CONFIRM) {
printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
goto out;
}
}
else {
if (!(flags & CONFIRM)) {
printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
goto out;
}
}
if (stateid->si_generation > stp->st_stateid.si_generation) {
printk("NFSD: preprocess_seqid_op: future stateid?!\n");
goto out;
}
status = nfserr_old_stateid;
if (stateid->si_generation < stp->st_stateid.si_generation) {
printk("NFSD: preprocess_seqid_op: old stateid!\n");
goto out;
}
/* XXX renew the client lease here */
status = nfs_ok;
out:
return status;
no_nfs4_stateid:
/*
* We determine whether this is a bad stateid or a replay,
* starting by trying to look up the stateowner.
* If stateowner is not found - stateid is bad.
*/
if (!(sop = find_stateowner_id(stateid->si_stateownerid))) {
printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
status = nfserr_bad_stateid;
goto out;
}
check_replay:
status = nfserr_bad_seqid;
if (seqid == sop->so_seqid) {
printk("NFSD: preprocess_seqid_op: retransmission?\n");
/* XXX will need to indicate replay to calling function here */
} else
printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
goto out;
}
int
nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
{
int status;
struct nfs4_stateowner *sop;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
oc->oc_stateowner = NULL;
down(&client_sema); /* XXX need finer grained locking */
if ((status = nfs4_preprocess_seqid_op(current_fh, oc->oc_seqid,
&oc->oc_req_stateid,
CHECK_FH | CONFIRM,
&oc->oc_stateowner, &stp)))
goto out;
sop = oc->oc_stateowner;
sop->so_confirmed = 1;
update_stateid(&stp->st_stateid);
memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
/* XXX renew the client lease here */
dprintk("NFSD: nfsd4_open_confirm: success, seqid=%d "
"stateid=(%08x/%08x/%08x/%08x)\n", oc->oc_seqid,
stp->st_stateid.si_boot,
stp->st_stateid.si_stateownerid,
stp->st_stateid.si_fileid,
stp->st_stateid.si_generation);
status = nfs_ok;
out:
up(&client_sema);
return status;
}
int
nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
{
int status;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
down(&client_sema); /* XXX need finer grained locking */
if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid,
&od->od_stateid,
CHECK_FH, &od->od_stateowner, &stp)))
goto out;
status = nfserr_inval;
if (od->od_share_access & ~stp->st_share_access) {
dprintk("NFSD:access not a subset current=%08x, desired=%08x\n",
stp->st_share_access, od->od_share_access);
goto out;
}
if (od->od_share_deny & ~stp->st_share_deny) {
dprintk("NFSD:deny not a subset current=%08x, desired=%08x\n",
stp->st_share_deny, od->od_share_deny);
goto out;
}
nfs4_file_downgrade(&stp->st_vfs_file,
stp->st_share_access & ~od->od_share_access);
stp->st_share_access = od->od_share_access;
stp->st_share_deny = od->od_share_deny;
update_stateid(&stp->st_stateid);
memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
status = nfs_ok;
out:
up(&client_sema);
return status;
}
int
nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
{
int status;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_close on file %.*s\n",
current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
down(&client_sema); /* XXX need finer grained locking */
if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid,
&close->cl_stateid,
CHECK_FH,
&close->cl_stateowner, &stp)))
goto out;
/*
* Return success, but first update the stateid.
*/
status = nfs_ok;
update_stateid(&stp->st_stateid);
memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
/* release_open_state() calls nfsd_close() if needed */
release_open_state(stp);
out:
up(&client_sema);
return status;
}
void void
nfs4_state_init(void) nfs4_state_init(void)
{ {
...@@ -1172,7 +1608,14 @@ nfs4_state_init(void) ...@@ -1172,7 +1608,14 @@ nfs4_state_init(void)
} }
for (i = 0; i < OWNER_HASH_SIZE; i++) { for (i = 0; i < OWNER_HASH_SIZE; i++) {
INIT_LIST_HEAD(&ownerstr_hashtbl[i]); INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
INIT_LIST_HEAD(&ownerid_hashtbl[i]);
}
for (i = 0; i < OPENSTATEID_HASH_SIZE; i++) {
INIT_LIST_HEAD(&openstateid_hashtbl[i]);
} }
memset(&zerostateid, 0, sizeof(stateid_t));
memset(&onestateid, ~0, sizeof(stateid_t));
INIT_LIST_HEAD(&client_lru); INIT_LIST_HEAD(&client_lru);
init_MUTEX(&client_sema); init_MUTEX(&client_sema);
boot_time = get_seconds(); boot_time = get_seconds();
...@@ -1206,6 +1649,12 @@ __nfs4_state_shutdown(void) ...@@ -1206,6 +1649,12 @@ __nfs4_state_shutdown(void)
list_add_perfile, list_del_perfile); list_add_perfile, list_del_perfile);
dprintk("NFSD: add_perclient %d del_perclient %d\n", dprintk("NFSD: add_perclient %d del_perclient %d\n",
add_perclient, del_perclient); add_perclient, del_perclient);
dprintk("NFSD: alloc_file %d free_file %d\n",
alloc_file, free_file);
dprintk("NFSD: alloc_sowner %d free_sowner %d\n",
alloc_sowner, free_sowner);
dprintk("NFSD: vfsopen %d vfsclose %d\n",
vfsopen, vfsclose);
} }
void void
......
...@@ -659,6 +659,34 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) ...@@ -659,6 +659,34 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
DECODE_TAIL; DECODE_TAIL;
} }
static int
nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
{
DECODE_HEAD;
READ_BUF(4 + sizeof(stateid_t));
READ32(open_conf->oc_req_stateid.si_generation);
COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
READ32(open_conf->oc_seqid);
DECODE_TAIL;
}
static int
nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
{
DECODE_HEAD;
READ_BUF(4 + sizeof(stateid_t));
READ32(open_down->od_stateid.si_generation);
COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
READ32(open_down->od_seqid);
READ32(open_down->od_share_access);
READ32(open_down->od_share_deny);
DECODE_TAIL;
}
static int static int
nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
{ {
...@@ -953,6 +981,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -953,6 +981,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
case OP_OPEN: case OP_OPEN:
op->status = nfsd4_decode_open(argp, &op->u.open); op->status = nfsd4_decode_open(argp, &op->u.open);
break; break;
case OP_OPEN_CONFIRM:
op->status = nfsd4_decode_open_confirm(argp, &op->u.open_confirm);
break;
case OP_OPEN_DOWNGRADE:
op->status = nfsd4_decode_open_downgrade(argp, &op->u.open_downgrade);
break;
case OP_PUTFH: case OP_PUTFH:
op->status = nfsd4_decode_putfh(argp, &op->u.putfh); op->status = nfsd4_decode_putfh(argp, &op->u.putfh);
break; break;
...@@ -1057,6 +1091,21 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -1057,6 +1091,21 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
} while (0) } while (0)
#define ADJUST_ARGS() resp->p = p #define ADJUST_ARGS() resp->p = p
/*
* Routine for encoding the result of a
* "seqid-mutating" NFSv4 operation. This is
* where seqids are incremented
*/
#define ENCODE_SEQID_OP_TAIL(stateowner) \
BUG_ON(!stateowner); \
if (seqid_mutating_err(nfserr) && stateowner) { \
if (stateowner->so_confirmed) \
stateowner->so_seqid++; \
} \
return nfserr;
static u32 nfs4_ftypes[16] = { static u32 nfs4_ftypes[16] = {
NF4BAD, NF4FIFO, NF4CHR, NF4BAD, NF4BAD, NF4FIFO, NF4CHR, NF4BAD,
NF4DIR, NF4BAD, NF4BLK, NF4BAD, NF4DIR, NF4BAD, NF4BLK, NF4BAD,
...@@ -1701,6 +1750,36 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open ...@@ -1701,6 +1750,36 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open
} }
} }
static int
nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_confirm *oc)
{
ENCODE_HEAD;
if (!nfserr) {
RESERVE_SPACE(sizeof(stateid_t));
WRITE32(oc->oc_resp_stateid.si_generation);
WRITEMEM(&oc->oc_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
ADJUST_ARGS();
}
ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
}
static int
nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_downgrade *od)
{
ENCODE_HEAD;
if (!nfserr) {
RESERVE_SPACE(sizeof(stateid_t));
WRITE32(od->od_stateid.si_generation);
WRITEMEM(&od->od_stateid.si_opaque, sizeof(stateid_opaque_t));
ADJUST_ARGS();
}
ENCODE_SEQID_OP_TAIL(od->od_stateowner);
}
static int static int
nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read) nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
{ {
...@@ -2013,6 +2092,12 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) ...@@ -2013,6 +2092,12 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
case OP_OPEN: case OP_OPEN:
nfsd4_encode_open(resp, op->status, &op->u.open); nfsd4_encode_open(resp, op->status, &op->u.open);
break; break;
case OP_OPEN_CONFIRM:
nfsd4_encode_open_confirm(resp, op->status, &op->u.open_confirm);
break;
case OP_OPEN_DOWNGRADE:
nfsd4_encode_open_downgrade(resp, op->status, &op->u.open_downgrade);
break;
case OP_PUTFH: case OP_PUTFH:
break; break;
case OP_PUTROOTFH: case OP_PUTROOTFH:
......
...@@ -175,32 +175,14 @@ static struct file_operations transaction_ops = { ...@@ -175,32 +175,14 @@ static struct file_operations transaction_ops = {
extern struct seq_operations nfs_exports_op; extern struct seq_operations nfs_exports_op;
static int exports_open(struct inode *inode, struct file *file) static int exports_open(struct inode *inode, struct file *file)
{ {
int res; return seq_open(file, &nfs_exports_op);
char *namebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (namebuf == NULL)
return -ENOMEM;
res = seq_open(file, &nfs_exports_op);
if (res)
kfree(namebuf);
else
((struct seq_file *)file->private_data)->private = namebuf;
return res;
}
static int exports_release(struct inode *inode, struct file *file)
{
struct seq_file *m = (struct seq_file *)file->private_data;
kfree(m->private);
m->private = NULL;
return seq_release(inode, file);
} }
static struct file_operations exports_operations = { static struct file_operations exports_operations = {
.open = exports_open, .open = exports_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = exports_release, .release = seq_release,
}; };
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
......
...@@ -100,7 +100,18 @@ ...@@ -100,7 +100,18 @@
NFSERR_RECLAIM_CONFLICT = 10035,/* v4 */ NFSERR_RECLAIM_CONFLICT = 10035,/* v4 */
NFSERR_BAD_XDR = 10036, /* v4 */ NFSERR_BAD_XDR = 10036, /* v4 */
NFSERR_LOCKS_HELD = 10037, /* v4 */ NFSERR_LOCKS_HELD = 10037, /* v4 */
NFSERR_REPLAY_ME = 10038 /* v4 */ NFSERR_OPENMODE = 10038, /* v4 */
NFSERR_BADOWNER = 10039, /* v4 */
NFSERR_BADCHAR = 10040, /* v4 */
NFSERR_BADNAME = 10041, /* v4 */
NFSERR_BAD_RANGE = 10042, /* v4 */
NFSERR_LOCK_NOTSUPP = 10043, /* v4 */
NFSERR_OP_ILLEGAL = 10044, /* v4 */
NFSERR_DEADLOCK = 10045, /* v4 */
NFSERR_FILE_OPEN = 10046, /* v4 */
NFSERR_ADMIN_REVOKED = 10047, /* v4 */
NFSERR_CB_PATH_DOWN = 10048, /* v4 */
NFSERR_REPLAY_ME = 10049 /* v4 */
}; };
/* NFSv2 file types - beware, these are not the same in NFSv3 */ /* NFSv2 file types - beware, these are not the same in NFSv3 */
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#define NFS4_SHARE_ACCESS_READ 0x0001 #define NFS4_SHARE_ACCESS_READ 0x0001
#define NFS4_SHARE_ACCESS_WRITE 0x0002 #define NFS4_SHARE_ACCESS_WRITE 0x0002
#define NFS4_SHARE_ACCESS_BOTH 0x0003 #define NFS4_SHARE_ACCESS_BOTH 0x0003
#define NFS4_SHARE_DENY_READ 0x0001
#define NFS4_SHARE_DENY_WRITE 0x0002
#define NFS4_SET_TO_SERVER_TIME 0 #define NFS4_SET_TO_SERVER_TIME 0
#define NFS4_SET_TO_CLIENT_TIME 1 #define NFS4_SET_TO_CLIENT_TIME 1
......
...@@ -189,6 +189,7 @@ void nfsd_lockd_shutdown(void); ...@@ -189,6 +189,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_not_same __constant_htonl(NFSERR_NOT_SAME) #define nfserr_not_same __constant_htonl(NFSERR_NOT_SAME)
#define nfserr_readdir_nospc __constant_htonl(NFSERR_READDIR_NOSPC) #define nfserr_readdir_nospc __constant_htonl(NFSERR_READDIR_NOSPC)
#define nfserr_bad_xdr __constant_htonl(NFSERR_BAD_XDR) #define nfserr_bad_xdr __constant_htonl(NFSERR_BAD_XDR)
#define nfserr_openmode __constant_htonl(NFSERR_OPENMODE)
/* error codes for internal use */ /* error codes for internal use */
/* if a request fails due to kmalloc failure, it gets dropped. /* if a request fails due to kmalloc failure, it gets dropped.
......
...@@ -59,6 +59,12 @@ typedef struct { ...@@ -59,6 +59,12 @@ typedef struct {
#define si_stateownerid si_opaque.so_stateownerid #define si_stateownerid si_opaque.so_stateownerid
#define si_fileid si_opaque.so_fileid #define si_fileid si_opaque.so_fileid
extern stateid_t zerostateid;
extern stateid_t onestateid;
#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
/* /*
* struct nfs4_client - one per client. Clientids live here. * struct nfs4_client - one per client. Clientids live here.
* o Each nfs4_client is hashed by clientid. * o Each nfs4_client is hashed by clientid.
...@@ -83,16 +89,12 @@ struct nfs4_client { ...@@ -83,16 +89,12 @@ struct nfs4_client {
nfs4_verifier cl_confirm; /* generated by server */ nfs4_verifier cl_confirm; /* generated by server */
}; };
extern time_t nfs4_laundromat(void);
int nfsd4_renew(clientid_t *clid);
static inline void static inline void
update_stateid(stateid_t *stateid) update_stateid(stateid_t *stateid)
{ {
stateid->si_generation++; stateid->si_generation++;
} }
/* /*
* nfs4_stateowner can either be an open_owner, or (eventually) a lock_owner * nfs4_stateowner can either be an open_owner, or (eventually) a lock_owner
* *
...@@ -100,6 +102,7 @@ stateid->si_generation++; ...@@ -100,6 +102,7 @@ stateid->si_generation++;
* reverences when we release a stateowner. * reverences when we release a stateowner.
*/ */
struct nfs4_stateowner { struct nfs4_stateowner {
struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */ struct list_head so_strhash; /* hash by op_name */
struct list_head so_perclient; /* nfs4_client->cl_perclient */ struct list_head so_perclient; /* nfs4_client->cl_perclient */
struct list_head so_peropenstate; /* list: nfs4_stateid */ struct list_head so_peropenstate; /* list: nfs4_stateid */
...@@ -136,6 +139,7 @@ struct nfs4_file { ...@@ -136,6 +139,7 @@ struct nfs4_file {
*/ */
struct nfs4_stateid { struct nfs4_stateid {
struct list_head st_hash; /* openstateid_hashtbl[]*/
struct list_head st_perfile; /* file_hashtbl[]*/ struct list_head st_perfile; /* file_hashtbl[]*/
struct list_head st_peropenstate; /* nfs4_stateowner->so_peropenstate */ struct list_head st_peropenstate; /* nfs4_stateowner->so_peropenstate */
struct nfs4_stateowner * st_stateowner; struct nfs4_stateowner * st_stateowner;
...@@ -147,4 +151,22 @@ struct nfs4_stateid { ...@@ -147,4 +151,22 @@ struct nfs4_stateid {
unsigned int st_share_deny; unsigned int st_share_deny;
}; };
/* flags for preprocess_seqid_op() */
#define CHECK_FH 0x00000001
#define CONFIRM 0x00000002
#define seqid_mutating_err(err) \
(((err) != nfserr_stale_clientid) && \
((err) != nfserr_bad_seqid) && \
((err) != nfserr_stale_stateid) && \
((err) != nfserr_bad_stateid))
extern time_t nfs4_laundromat(void);
extern int nfsd4_renew(clientid_t *clid);
extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh,
stateid_t *stateid, int flags, struct nfs4_stateid **stpp);
extern int nfs4_share_conflict(struct svc_fh *current_fh,
unsigned int deny_type);
extern void nfsd4_lock_state(void);
extern void nfsd4_unlock_state(void);
#endif /* NFSD4_STATE_H */ #endif /* NFSD4_STATE_H */
...@@ -68,6 +68,7 @@ struct nfsd4_access { ...@@ -68,6 +68,7 @@ struct nfsd4_access {
struct nfsd4_close { struct nfsd4_close {
u32 cl_seqid; /* request */ u32 cl_seqid; /* request */
stateid_t cl_stateid; /* request+response */ stateid_t cl_stateid; /* request+response */
struct nfs4_stateowner * cl_stateowner; /* response */
}; };
struct nfsd4_commit { struct nfsd4_commit {
...@@ -147,6 +148,22 @@ struct nfsd4_open { ...@@ -147,6 +148,22 @@ struct nfsd4_open {
#define op_iattr u.iattr #define op_iattr u.iattr
#define op_verf u.verf #define op_verf u.verf
struct nfsd4_open_confirm {
stateid_t oc_req_stateid /* request */;
u32 oc_seqid /* request */;
stateid_t oc_resp_stateid /* response */;
struct nfs4_stateowner * oc_stateowner; /* response */
};
struct nfsd4_open_downgrade {
stateid_t od_stateid;
u32 od_seqid;
u32 od_share_access;
u32 od_share_deny;
struct nfs4_stateowner *od_stateowner;
};
struct nfsd4_read { struct nfsd4_read {
stateid_t rd_stateid; /* request */ stateid_t rd_stateid; /* request */
u64 rd_offset; /* request */ u64 rd_offset; /* request */
...@@ -252,6 +269,8 @@ struct nfsd4_op { ...@@ -252,6 +269,8 @@ struct nfsd4_op {
struct nfsd4_lookup lookup; struct nfsd4_lookup lookup;
struct nfsd4_verify nverify; struct nfsd4_verify nverify;
struct nfsd4_open open; struct nfsd4_open open;
struct nfsd4_open_confirm open_confirm;
struct nfsd4_open_downgrade open_downgrade;
struct nfsd4_putfh putfh; struct nfsd4_putfh putfh;
struct nfsd4_read read; struct nfsd4_read read;
struct nfsd4_readdir readdir; struct nfsd4_readdir readdir;
...@@ -315,16 +334,27 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) ...@@ -315,16 +334,27 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
} }
int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *); int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *);
int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *, struct nfsd4_compoundargs *); int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *,
int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *, struct nfsd4_compoundres *); struct nfsd4_compoundargs *);
int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *,
struct nfsd4_compoundres *);
void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval); struct dentry *dentry, u32 *buffer, int *countp,
extern int nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid); u32 *bmval);
extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm); extern int nfsd4_setclientid(struct svc_rqst *rqstp,
struct nfsd4_setclientid *setclid);
extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
struct nfsd4_setclientid_confirm *setclientid_confirm);
extern int nfsd4_process_open1(struct nfsd4_open *open); extern int nfsd4_process_open1(struct nfsd4_open *open);
extern int nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open); extern int nfsd4_process_open2(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open *open);
extern int nfsd4_open_confirm(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open_confirm *oc);
extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct nfsd4_close *close);
extern int nfsd4_open_downgrade(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open_downgrade *od);
#endif #endif
/* /*
......
...@@ -80,8 +80,7 @@ struct cache_detail { ...@@ -80,8 +80,7 @@ struct cache_detail {
int (*cache_show)(struct seq_file *m, int (*cache_show)(struct seq_file *m,
struct cache_detail *cd, struct cache_detail *cd,
struct cache_head *h, struct cache_head *h);
char *pbuf);
/* fields below this comment are for internal use /* fields below this comment are for internal use
* and should not be touched by cache owners * and should not be touched by cache owners
......
...@@ -41,7 +41,7 @@ static void __unhash_process(struct task_struct *p) ...@@ -41,7 +41,7 @@ static void __unhash_process(struct task_struct *p)
detach_pid(p, PIDTYPE_PGID); detach_pid(p, PIDTYPE_PGID);
detach_pid(p, PIDTYPE_SID); detach_pid(p, PIDTYPE_SID);
if (p->pid) if (p->pid)
per_cpu(process_counts, smp_processor_id())--; __get_cpu_var(process_counts)--;
} }
REMOVE_LINKS(p); REMOVE_LINKS(p);
......
...@@ -1006,7 +1006,7 @@ struct task_struct *copy_process(unsigned long clone_flags, ...@@ -1006,7 +1006,7 @@ struct task_struct *copy_process(unsigned long clone_flags,
attach_pid(p, PIDTYPE_PGID, p->pgrp); attach_pid(p, PIDTYPE_PGID, p->pgrp);
attach_pid(p, PIDTYPE_SID, p->session); attach_pid(p, PIDTYPE_SID, p->session);
if (p->pid) if (p->pid)
per_cpu(process_counts, smp_processor_id())++; __get_cpu_var(process_counts)++;
} else } else
link_pid(p, p->pids + PIDTYPE_TGID, &p->group_leader->pids[PIDTYPE_TGID].pid); link_pid(p, p->pids + PIDTYPE_TGID, &p->group_leader->pids[PIDTYPE_TGID].pid);
......
...@@ -156,8 +156,7 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer) ...@@ -156,8 +156,7 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
*/ */
void add_timer(struct timer_list *timer) void add_timer(struct timer_list *timer)
{ {
int cpu = get_cpu(); tvec_base_t *base = &get_cpu_var(tvec_bases);
tvec_base_t *base = &per_cpu(tvec_bases, cpu);
unsigned long flags; unsigned long flags;
BUG_ON(timer_pending(timer) || !timer->function); BUG_ON(timer_pending(timer) || !timer->function);
...@@ -168,7 +167,7 @@ void add_timer(struct timer_list *timer) ...@@ -168,7 +167,7 @@ void add_timer(struct timer_list *timer)
internal_add_timer(base, timer); internal_add_timer(base, timer);
timer->base = base; timer->base = base;
spin_unlock_irqrestore(&base->lock, flags); spin_unlock_irqrestore(&base->lock, flags);
put_cpu(); put_cpu_var(tvec_bases);
} }
/*** /***
...@@ -231,7 +230,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires) ...@@ -231,7 +230,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
return 1; return 1;
spin_lock_irqsave(&timer->lock, flags); spin_lock_irqsave(&timer->lock, flags);
new_base = &per_cpu(tvec_bases, smp_processor_id()); new_base = &__get_cpu_var(tvec_bases);
repeat: repeat:
old_base = timer->base; old_base = timer->base;
...@@ -789,7 +788,7 @@ seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; ...@@ -789,7 +788,7 @@ seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
*/ */
static void run_timer_softirq(struct softirq_action *h) static void run_timer_softirq(struct softirq_action *h)
{ {
tvec_base_t *base = &per_cpu(tvec_bases, smp_processor_id()); tvec_base_t *base = &__get_cpu_var(tvec_bases);
if (time_after_eq(jiffies, base->timer_jiffies)) if (time_after_eq(jiffies, base->timer_jiffies))
__run_timers(base); __run_timers(base);
......
...@@ -213,21 +213,19 @@ void balance_dirty_pages(struct address_space *mapping) ...@@ -213,21 +213,19 @@ void balance_dirty_pages(struct address_space *mapping)
void balance_dirty_pages_ratelimited(struct address_space *mapping) void balance_dirty_pages_ratelimited(struct address_space *mapping)
{ {
static DEFINE_PER_CPU(int, ratelimits) = 0; static DEFINE_PER_CPU(int, ratelimits) = 0;
int cpu;
long ratelimit; long ratelimit;
ratelimit = ratelimit_pages; ratelimit = ratelimit_pages;
if (dirty_exceeded) if (dirty_exceeded)
ratelimit = 8; ratelimit = 8;
cpu = get_cpu(); if (get_cpu_var(ratelimits)++ >= ratelimit) {
if (per_cpu(ratelimits, cpu)++ >= ratelimit) { __get_cpu_var(ratelimits) = 0;
per_cpu(ratelimits, cpu) = 0; put_cpu_var(ratelimits);
put_cpu();
balance_dirty_pages(mapping); balance_dirty_pages(mapping);
return; return;
} }
put_cpu(); put_cpu_var(ratelimits);
} }
/* /*
......
...@@ -477,16 +477,15 @@ DEFINE_PER_CPU(struct pte_chain *, local_pte_chain) = 0; ...@@ -477,16 +477,15 @@ DEFINE_PER_CPU(struct pte_chain *, local_pte_chain) = 0;
*/ */
void __pte_chain_free(struct pte_chain *pte_chain) void __pte_chain_free(struct pte_chain *pte_chain)
{ {
int cpu = get_cpu();
struct pte_chain **pte_chainp; struct pte_chain **pte_chainp;
pte_chainp = &get_cpu_var(local_pte_chain);
if (pte_chain->next_and_idx) if (pte_chain->next_and_idx)
pte_chain->next_and_idx = 0; pte_chain->next_and_idx = 0;
pte_chainp = &per_cpu(local_pte_chain, cpu);
if (*pte_chainp) if (*pte_chainp)
kmem_cache_free(pte_chain_cache, *pte_chainp); kmem_cache_free(pte_chain_cache, *pte_chainp);
*pte_chainp = pte_chain; *pte_chainp = pte_chain;
put_cpu(); put_cpu_var(local_pte_chain);
} }
/* /*
...@@ -501,21 +500,19 @@ void __pte_chain_free(struct pte_chain *pte_chain) ...@@ -501,21 +500,19 @@ void __pte_chain_free(struct pte_chain *pte_chain)
*/ */
struct pte_chain *pte_chain_alloc(int gfp_flags) struct pte_chain *pte_chain_alloc(int gfp_flags)
{ {
int cpu;
struct pte_chain *ret; struct pte_chain *ret;
struct pte_chain **pte_chainp; struct pte_chain **pte_chainp;
if (gfp_flags & __GFP_WAIT) if (gfp_flags & __GFP_WAIT)
might_sleep(); might_sleep();
cpu = get_cpu(); pte_chainp = &get_cpu_var(local_pte_chain);
pte_chainp = &per_cpu(local_pte_chain, cpu);
if (*pte_chainp) { if (*pte_chainp) {
ret = *pte_chainp; ret = *pte_chainp;
*pte_chainp = NULL; *pte_chainp = NULL;
put_cpu(); put_cpu_var(local_pte_chain);
} else { } else {
put_cpu(); put_cpu_var(local_pte_chain);
ret = kmem_cache_alloc(pte_chain_cache, gfp_flags); ret = kmem_cache_alloc(pte_chain_cache, gfp_flags);
} }
return ret; return ret;
......
...@@ -112,35 +112,34 @@ static DEFINE_PER_CPU(struct pagevec, lru_add_active_pvecs) = { 0, }; ...@@ -112,35 +112,34 @@ static DEFINE_PER_CPU(struct pagevec, lru_add_active_pvecs) = { 0, };
void lru_cache_add(struct page *page) void lru_cache_add(struct page *page)
{ {
struct pagevec *pvec = &per_cpu(lru_add_pvecs, get_cpu()); struct pagevec *pvec = &get_cpu_var(lru_add_pvecs);
page_cache_get(page); page_cache_get(page);
if (!pagevec_add(pvec, page)) if (!pagevec_add(pvec, page))
__pagevec_lru_add(pvec); __pagevec_lru_add(pvec);
put_cpu(); put_cpu_var(lru_add_pvecs);
} }
void lru_cache_add_active(struct page *page) void lru_cache_add_active(struct page *page)
{ {
struct pagevec *pvec = &per_cpu(lru_add_active_pvecs, get_cpu()); struct pagevec *pvec = &get_cpu_var(lru_add_active_pvecs);
page_cache_get(page); page_cache_get(page);
if (!pagevec_add(pvec, page)) if (!pagevec_add(pvec, page))
__pagevec_lru_add_active(pvec); __pagevec_lru_add_active(pvec);
put_cpu(); put_cpu_var(lru_add_active_pvecs);
} }
void lru_add_drain(void) void lru_add_drain(void)
{ {
int cpu = get_cpu(); struct pagevec *pvec = &get_cpu_var(lru_add_pvecs);
struct pagevec *pvec = &per_cpu(lru_add_pvecs, cpu);
if (pagevec_count(pvec)) if (pagevec_count(pvec))
__pagevec_lru_add(pvec); __pagevec_lru_add(pvec);
pvec = &per_cpu(lru_add_active_pvecs, cpu); pvec = &__get_cpu_var(lru_add_active_pvecs);
if (pagevec_count(pvec)) if (pagevec_count(pvec))
__pagevec_lru_add_active(pvec); __pagevec_lru_add_active(pvec);
put_cpu(); put_cpu_var(lru_add_pvecs);
} }
/* /*
......
...@@ -228,7 +228,7 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; ...@@ -228,7 +228,7 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
* On SMP we have one ICMP socket per-cpu. * On SMP we have one ICMP socket per-cpu.
*/ */
static DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL; static DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL;
#define icmp_socket per_cpu(__icmp_socket, smp_processor_id()) #define icmp_socket __get_cpu_var(__icmp_socket)
static __inline__ void icmp_xmit_lock(void) static __inline__ void icmp_xmit_lock(void)
{ {
......
...@@ -1018,7 +1018,6 @@ int qword_get(char **bpp, char *dest, int bufsize) ...@@ -1018,7 +1018,6 @@ int qword_get(char **bpp, char *dest, int bufsize)
struct handle { struct handle {
struct cache_detail *cd; struct cache_detail *cd;
char *pbuf;
}; };
static void *c_start(struct seq_file *m, loff_t *pos) static void *c_start(struct seq_file *m, loff_t *pos)
...@@ -1087,10 +1086,9 @@ static int c_show(struct seq_file *m, void *p) ...@@ -1087,10 +1086,9 @@ static int c_show(struct seq_file *m, void *p)
{ {
struct cache_head *cp = p; struct cache_head *cp = p;
struct cache_detail *cd = ((struct handle*)m->private)->cd; struct cache_detail *cd = ((struct handle*)m->private)->cd;
char *pbuf = ((struct handle*)m->private)->pbuf;
if (p == (void *)1) if (p == (void *)1)
return cd->cache_show(m, cd, NULL, pbuf); return cd->cache_show(m, cd, NULL);
ifdebug(CACHE) ifdebug(CACHE)
seq_printf(m, "# expiry=%ld refcnt=%d\n", seq_printf(m, "# expiry=%ld refcnt=%d\n",
...@@ -1102,7 +1100,7 @@ static int c_show(struct seq_file *m, void *p) ...@@ -1102,7 +1100,7 @@ static int c_show(struct seq_file *m, void *p)
else else
cache_put(cp, cd); cache_put(cp, cd);
return cd->cache_show(m, cd, cp, pbuf); return cd->cache_show(m, cd, cp);
} }
struct seq_operations cache_content_op = { struct seq_operations cache_content_op = {
...@@ -1115,26 +1113,19 @@ struct seq_operations cache_content_op = { ...@@ -1115,26 +1113,19 @@ struct seq_operations cache_content_op = {
static int content_open(struct inode *inode, struct file *file) static int content_open(struct inode *inode, struct file *file)
{ {
int res; int res;
char *namebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
struct handle *han; struct handle *han;
struct cache_detail *cd = PDE(inode)->data; struct cache_detail *cd = PDE(inode)->data;
if (namebuf == NULL)
return -ENOMEM;
han = kmalloc(sizeof(*han), GFP_KERNEL); han = kmalloc(sizeof(*han), GFP_KERNEL);
if (han == NULL) { if (han == NULL)
kfree(namebuf);
return -ENOMEM; return -ENOMEM;
}
han->pbuf = namebuf;
han->cd = cd; han->cd = cd;
res = seq_open(file, &cache_content_op); res = seq_open(file, &cache_content_op);
if (res) { if (res)
kfree(namebuf);
kfree(han); kfree(han);
} else else
((struct seq_file *)file->private_data)->private = han; ((struct seq_file *)file->private_data)->private = han;
return res; return res;
...@@ -1143,7 +1134,6 @@ static int content_release(struct inode *inode, struct file *file) ...@@ -1143,7 +1134,6 @@ static int content_release(struct inode *inode, struct file *file)
{ {
struct seq_file *m = (struct seq_file *)file->private_data; struct seq_file *m = (struct seq_file *)file->private_data;
struct handle *han = m->private; struct handle *han = m->private;
kfree(han->pbuf);
kfree(han); kfree(han);
m->private = NULL; m->private = NULL;
return seq_release(inode, file); return seq_release(inode, file);
......
...@@ -215,8 +215,7 @@ static int ip_map_parse(struct cache_detail *cd, ...@@ -215,8 +215,7 @@ static int ip_map_parse(struct cache_detail *cd,
static int ip_map_show(struct seq_file *m, static int ip_map_show(struct seq_file *m,
struct cache_detail *cd, struct cache_detail *cd,
struct cache_head *h, struct cache_head *h)
char *pbuf)
{ {
struct ip_map *im; struct ip_map *im;
struct in_addr addr; struct in_addr addr;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/suspend.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/ip.h> #include <net/ip.h>
...@@ -1190,6 +1191,9 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) ...@@ -1190,6 +1191,9 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
schedule_timeout(timeout); schedule_timeout(timeout);
if (current->flags & PF_FREEZE)
refrigerator(PF_IOTHREAD);
spin_lock_bh(&serv->sv_lock); spin_lock_bh(&serv->sv_lock);
remove_wait_queue(&rqstp->rq_wait, &wait); remove_wait_queue(&rqstp->rq_wait, &wait);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment