From 7a024f46b32347499dc4110b1edb8a4b3280a95c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:14:27 -0500 Subject: [PATCH] Pre-2.1.80.. I just put a pre-2.1.80 on ftp.kernel.org that should fix the fat-related problems. The reason I put it there is because I got several patches that fixed the FAT problems _and_ something else, and they all obviously clashed with each other so neither part got applied. So I'd ask people who sent me patches to maybe re-send the parts of the patches that are still relevant, Linus --- Rules.make | 8 +- arch/i386/defconfig | 1 + drivers/char/tuner.h | 1 + fs/dcache.c | 4 + fs/fat/cache.c | 10 +-- fs/fat/dir.c | 4 +- fs/fat/inode.c | 2 +- fs/fat/misc.c | 4 +- fs/fat/mmap.c | 8 +- fs/inode.c | 1 + fs/nfs/proc.c | 9 -- fs/vfat/namei.c | 171 ++++++++++++++++++++++++++++--------- include/asm-i386/uaccess.h | 87 ++++++++++++++++++- include/linux/dcache.h | 1 + include/linux/fs.h | 1 + include/linux/msdos_fs.h | 11 ++- kernel/ksyms.c | 2 + net/Config.in | 1 + net/core/Makefile | 4 + net/core/sock.c | 8 ++ net/ipv4/tcp_ipv4.c | 8 ++ net/netsyms.c | 4 + 22 files changed, 279 insertions(+), 71 deletions(-) diff --git a/Rules.make b/Rules.make index 8f7da991f891..63181e223532 100644 --- a/Rules.make +++ b/Rules.make @@ -56,7 +56,7 @@ first_rule: sub_dirs echo 'ifeq ($(strip $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@)),$$(strip $$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags %.o: %.s $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $< @@ -82,7 +82,7 @@ endif echo 'ifeq ($(strip $(EXTRA_LDFLAGS) $(ALL_O)),$$(strip $$(EXTRA_LDFLAGS) $$(ALL_O)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif # O_TARGET # @@ -96,7 +96,7 @@ $(L_TARGET): $(LX_OBJS) $(L_OBJS) echo 'ifeq ($(strip $(EXTRA_ARFLAGS) $(LX_OBJS) $(L_OBJS)),$$(strip $$(EXTRA_ARFLAGS) $$(LX_OBJS) $$(L_OBJS)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif # @@ -218,7 +218,7 @@ $(SYMTAB_OBJS): $(TOPDIR)/include/linux/modversions.h $(SYMTAB_OBJS:.o=.c) echo 'ifeq ($(strip $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB),$$(strip $$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif endif # CONFIG_MODULES diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 30369f009068..aa3f2a90c2ad 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -84,6 +84,7 @@ CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set +# CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set diff --git a/drivers/char/tuner.h b/drivers/char/tuner.h index 5b3cf012f78d..e3e7b889fe7d 100644 --- a/drivers/char/tuner.h +++ b/drivers/char/tuner.h @@ -54,6 +54,7 @@ struct tunertype { unchar UHF; unchar config; unchar I2C; + ushort IFPCoff; }; #endif diff --git a/fs/dcache.c b/fs/dcache.c index 4f3f08eb055f..a19ad233771b 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -67,6 +67,7 @@ static inline void dentry_iput(struct dentry * dentry) struct inode *inode = dentry->d_inode; if (inode) { dentry->d_inode = NULL; + list_del(&dentry->d_alias); if (dentry->d_op && dentry->d_op->d_iput) dentry->d_op->d_iput(dentry, inode); else @@ -508,6 +509,7 @@ printk("d_alloc: %d unused, pruning dcache\n", dentry_stat.nr_unused); INIT_LIST_HEAD(&dentry->d_hash); INIT_LIST_HEAD(&dentry->d_lru); INIT_LIST_HEAD(&dentry->d_subdirs); + INIT_LIST_HEAD(&dentry->d_alias); dentry->d_name.name = str; dentry->d_name.len = name->len; @@ -529,6 +531,8 @@ printk("d_alloc: %d unused, pruning dcache\n", dentry_stat.nr_unused); */ void d_instantiate(struct dentry *entry, struct inode * inode) { + if (inode) + list_add(&entry->d_alias, &inode->i_dentry); entry->d_inode = inode; } diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 5eb10002e15b..edc976bd4fb9 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -122,7 +122,7 @@ int fat_access(struct super_block *sb,int nr,int new_value) } -void cache_init(void) +void fat_cache_init(void) { static int initialized = 0; int count; @@ -138,7 +138,7 @@ void cache_init(void) } -void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) +void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) { struct fat_cache *walk; @@ -179,7 +179,7 @@ static void list_cache(void) #endif -void cache_add(struct inode *inode,int f_clu,int d_clu) +void fat_cache_add(struct inode *inode,int f_clu,int d_clu) { struct fat_cache *walk,*last; @@ -252,12 +252,12 @@ int fat_get_cluster(struct inode *inode,int cluster) if (!(nr = MSDOS_I(inode)->i_start)) return 0; if (!cluster) return nr; count = 0; - for (cache_lookup(inode,cluster,&count,&nr); count < cluster; + for (fat_cache_lookup(inode,cluster,&count,&nr); count < cluster; count++) { if ((nr = fat_access(inode->i_sb,nr,-1)) == -1) return 0; if (!nr) return 0; } - cache_add(inode,cluster,nr); + fat_cache_add(inode,cluster,nr); return nr; } diff --git a/fs/fat/dir.c b/fs/fat/dir.c index d79369289027..23b15726c455 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -237,6 +237,7 @@ int fat_readdirx( char bufname[14]; char *ptname = bufname; int dotoffset = 0; + int was_long = is_long; if (is_long) { unsigned char sum; @@ -247,6 +248,7 @@ int fat_readdirx( if (sum != alias_checksum) { PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum)); is_long = 0; + long_slots = 0; } if (utf8) { long_len = utf8_wcstombs(longname, (__u16 *) unicode, sizeof(longname)); @@ -290,7 +292,7 @@ int fat_readdirx( if (both) bufname[i+dotoffset] = '\0'; spos = oldpos; - if (is_long) { + if (was_long) { spos = filp->f_pos - sizeof(struct msdos_dir_entry); } else { long_slots = 0; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index d84c2c2e0eb9..d1c43bf17acd 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -377,7 +377,7 @@ fat_read_super(struct super_block *sb, void *data, int silent) /* N.B. we should parse directly into the sb structure */ memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options)); - cache_init(); + fat_cache_init(); lock_super(sb); if( blksize > 1024 ) { diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 38cd5cb8e681..dc3a2545ce8a 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -194,7 +194,7 @@ printk("set to %x\n",fat_access(sb,nr,-1)); */ file_cluster = 0; if ((curr = MSDOS_I(inode)->i_start) != 0) { - cache_lookup(inode,INT_MAX,&last,&curr); + fat_cache_lookup(inode,INT_MAX,&last,&curr); file_cluster = last; while (curr && curr != -1){ PRINTK ((".")); @@ -242,7 +242,7 @@ if (last) printk("next set to %d\n",fat_access(sb,last,-1)); printk ("file_cluster badly computed!!! %d <> %ld\n" ,file_cluster,inode->i_blocks/cluster_size); }else{ - cache_add(inode,file_cluster,nr); + fat_cache_add(inode,file_cluster,nr); } inode->i_blocks += cluster_size; if (S_ISDIR(inode->i_mode)) { diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c index e01bc14cb300..a95db457f75d 100644 --- a/fs/fat/mmap.c +++ b/fs/fat/mmap.c @@ -118,11 +118,13 @@ int fat_mmap(struct file * file, struct vm_area_struct * vma) } -int fat_readpage(struct inode * inode, struct page * page) +int fat_readpage(struct dentry * dentry, struct page * page) { + struct inode * inode = dentry->d_inode; if(MSDOS_SB(inode->i_sb)->cvf_format) - if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage) - return MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page); + if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage) + return MSDOS_SB(inode->i_sb)->cvf_format + ->cvf_readpage(inode,page); printk("fat_readpage called with no handler (shouldn't happen)\n"); return -1; diff --git a/fs/inode.c b/fs/inode.c index bfe9e97df319..357f5591d23e 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -127,6 +127,7 @@ static inline void init_once(struct inode * inode) memset(inode, 0, sizeof(*inode)); init_waitqueue(&inode->i_wait); INIT_LIST_HEAD(&inode->i_hash); + INIT_LIST_HEAD(&inode->i_dentry); sema_init(&inode->i_sem, 1); } diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 91fba9b2ace7..38a9513dc6c1 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -43,11 +43,6 @@ #include -/* - * If NFS_DEBUG is defined, you can toggle NFS debugging by causing - * a lookup of "__xyzzy__". Just cd to an NFS-mounted filesystem and type - * 'ls __xyzzy__' to turn on debugging. - */ #ifdef NFS_DEBUG # define NFSDBG_FACILITY NFSDBG_PROC #endif @@ -90,10 +85,6 @@ nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name, int status; dprintk("NFS call lookup %s\n", name); -#ifdef RPC_DEBUG - if (!strcmp(name, "__xyzzy__")) - nfs_debug = ~nfs_debug; -#endif status = rpc_call(server->client, NFSPROC_LOOKUP, &arg, &res, 0); dprintk("NFS reply lookup: %d\n", status); return status; diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index b5c6aaf4017b..fb302376554c 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -57,6 +57,38 @@ void vfat_read_inode(struct inode *inode); static int vfat_valid_shortname(const char *,int, int, int); static int vfat_format_name(const char *, int, char *, int, int); static int vfat_valid_longname(const char *, int, int, int); +static int vfat_hashi(struct dentry *parent, struct qstr *qstr); +static int vfat_hash(struct dentry *parent, struct qstr *qstr); +static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); +static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b); +static int vfat_revalidate(struct dentry *dentry); + +static struct dentry_operations vfat_dentry_ops[4] = { + { + NULL, /* d_revalidate */ + vfat_hashi, + vfat_cmpi, + NULL /* d_delete */ + }, + { + vfat_revalidate, + vfat_hashi, + vfat_cmpi, + NULL /* d_delete */ + }, + { + NULL, /* d_revalidate */ + vfat_hash, + vfat_cmp, + NULL /* d_delete */ + }, + { + vfat_revalidate, + vfat_hash, + vfat_cmp, + NULL /* d_delete */ + } +}; static int strnicmp(const char *s1, const char *s2, int len) { @@ -80,6 +112,13 @@ void vfat_put_super(struct super_block *sb) MOD_DEC_USE_COUNT; } +static int vfat_revalidate(struct dentry *dentry) +{ + if (dentry->d_time == dentry->d_parent->d_inode->i_version) { + return 1; + } + return 0; +} static struct super_operations vfat_sops = { vfat_read_inode, @@ -165,6 +204,27 @@ static int parse_options(char *options, struct fat_mount_options *opts) * return ENOENT or EINVAL as appropriate. */ static int vfat_hash(struct dentry *dentry, struct qstr *qstr) +{ + const char *name; + int len; + + len = qstr->len; + name = qstr->name; + while (len && name[len-1] == '.') + len--; + + qstr->hash = full_name_hash(name, len); + + return 0; +} + +/* + * Compute the hash for the vfat name corresponding to the dentry. + * Note: if the name is invalid, we leave the hash code unchanged so + * that the existing dentry can be used. The vfat fs routines will + * return ENOENT or EINVAL as appropriate. + */ +static int vfat_hashi(struct dentry *dentry, struct qstr *qstr) { const char *name; int len; @@ -187,9 +247,9 @@ static int vfat_hash(struct dentry *dentry, struct qstr *qstr) } /* - * Compare two vfat names. + * Case insensitive compare of two vfat names. */ -static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) +static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) { int alen, blen; @@ -200,18 +260,33 @@ static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) alen--; while (blen && b->name[blen-1] == '.') blen--; - if (alen != blen) - return 1; - - return strnicmp(a->name, b->name, alen); + if (alen == blen) { + if (strnicmp(a->name, b->name, alen) == 0) + return 0; + } + return 1; } -static struct dentry_operations vfat_dentry_operations = { - NULL, /* d_revalidate */ - vfat_hash, - vfat_cmp, - NULL /* d_delete */ -}; +/* + * Case sensitive compare of two vfat names. + */ +static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) +{ + int alen, blen; + + /* A filename cannot end in '.' or we treat it like it has none */ + alen = a->len; + blen = b->len; + while (alen && a->name[alen-1] == '.') + alen--; + while (blen && b->name[blen-1] == '.') + blen--; + if (alen == blen) { + if (strncmp(a->name, b->name, alen) == 0) + return 0; + } + return 1; +} struct super_block *vfat_read_super(struct super_block *sb,void *data, int silent) @@ -235,7 +310,9 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data, } else { MSDOS_SB(sb)->options.dotsOK = 0; if (MSDOS_SB(sb)->options.name_check != 's') { - sb->s_root->d_op = &vfat_dentry_operations; + sb->s_root->d_op = &vfat_dentry_ops[0]; + } else { + sb->s_root->d_op = &vfat_dentry_ops[2]; } } @@ -321,7 +398,7 @@ static char replace_chars[] = "[];,+="; static int vfat_find(struct inode *dir,struct qstr* name, int find_long,int new_filename,int is_dir, - struct slot_info *sinfo_out); + struct vfat_slot_info *sinfo_out); /* Checks the validity of a long MS-DOS filename */ /* Returns negative number on error, 0 for a normal @@ -519,7 +596,7 @@ static int vfat_create_shortname(struct inode *dir, const char *name, int res; int spaces; char buf[8]; - struct slot_info sinfo; + struct vfat_slot_info sinfo; const char *name_start; struct qstr qname; @@ -778,7 +855,6 @@ xlate_to_uni(const char *name, int len, char *outname, int *outlen, len--; op = outname; if (nls) { - /* XXX: i is incorrectly computed. */ for (i = 0, ip = name, op = outname, *outlen = 0; i < len && *outlen <= 260; i++, *outlen += 1) { @@ -992,7 +1068,7 @@ static int vfat_readdir_cb( } static int vfat_find(struct inode *dir,struct qstr* qname, - int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out) + int find_long, int new_filename,int is_dir,struct vfat_slot_info *sinfo_out) { struct super_block *sb = dir->i_sb; struct vfat_find_info vf; @@ -1118,37 +1194,36 @@ cleanup: int vfat_lookup(struct inode *dir,struct dentry *dentry) { int res; - struct slot_info sinfo; + struct vfat_slot_info sinfo; struct inode *result; + int table; PRINTK (("vfat_lookup: name=%s, len=%d\n", dentry->d_name.name, dentry->d_name.len)); - if (MSDOS_SB(dir->i_sb)->options.name_check != 's') { - dentry->d_op = &vfat_dentry_operations; - } + table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0; + dentry->d_op = &vfat_dentry_ops[table]; result = NULL; if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0) { - d_add(dentry,NULL); - return 0; + result = NULL; + table++; + goto error; } PRINTK (("vfat_lookup 4.5\n")); if (!(result = iget(dir->i_sb,sinfo.ino))) return -EACCES; PRINTK (("vfat_lookup 5\n")); - if (!result->i_sb || - (result->i_sb->s_magic != MSDOS_SUPER_MAGIC)) { - /* crossed a mount point into a non-msdos fs */ - d_add(dentry,NULL); - return 0; - } if (MSDOS_I(result)->i_busy) { /* mkdir in progress */ iput(result); - d_add(dentry,NULL); - return 0; + result = NULL; + table++; + goto error; } PRINTK (("vfat_lookup 6\n")); +error: + dentry->d_op = &vfat_dentry_ops[table]; + dentry->d_time = dentry->d_parent->d_inode->i_version; d_add(dentry,result); return 0; } @@ -1162,7 +1237,7 @@ static int vfat_create_entry(struct inode *dir,struct qstr* qname, loff_t offset; struct buffer_head *bh; struct msdos_dir_entry *de; - struct slot_info sinfo; + struct vfat_slot_info sinfo; *result=0; PRINTK(("vfat_create_entry 1\n")); @@ -1210,6 +1285,7 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode) if (res < 0) { PRINTK(("vfat_create: unable to get new entry\n")); } else { + dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,result); } return res; @@ -1388,7 +1464,7 @@ static int vfat_unlink_free_ino(struct inode *dir,struct buffer_head *bh, return 0; } -static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo, +static int vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, struct buffer_head **bh,struct dentry* dentry, int is_dir,int nospc) { @@ -1422,13 +1498,31 @@ static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo, return 0; } +static void vfat_delete_dentries(struct dentry *dentry) +{ + struct list_head *head, *next, *tmp; + struct dentry *alias; + + head = &dentry->d_inode->i_dentry; + if (dentry->d_inode) { + next = dentry->d_inode->i_dentry.next; + while (next != head) { + tmp = next; + next = tmp->next; + alias = list_entry(tmp, struct dentry, d_alias); + d_delete(alias); + } + } else { + d_delete(dentry); + } +} static int vfat_rmdirx(struct inode *dir,struct dentry* dentry) { struct super_block *sb = dir->i_sb; int res; struct buffer_head *bh; - struct slot_info sinfo; + struct vfat_slot_info sinfo; res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo); @@ -1450,7 +1544,7 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry) int res; res = vfat_rmdirx(dir, dentry); if (res >= 0) { - d_delete(dentry); + vfat_delete_dentries(dentry); } return res; } @@ -1463,7 +1557,7 @@ static int vfat_unlinkx( struct super_block *sb = dir->i_sb; int res; struct buffer_head *bh; - struct slot_info sinfo; + struct vfat_slot_info sinfo; bh = NULL; res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo); @@ -1498,6 +1592,7 @@ int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode) res = vfat_create_dotdirs(inode, dir); fat_unlock_creation(); MSDOS_I(inode)->i_busy = 0; + dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,inode); if (res < 0) { if (vfat_rmdir(dir,dentry) < 0) @@ -1513,7 +1608,7 @@ int vfat_unlink(struct inode *dir,struct dentry* dentry) res = vfat_unlinkx (dir,dentry,1); if (res >= 0) { - d_delete(dentry); + vfat_delete_dentries(dentry); } return res; } @@ -1540,7 +1635,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, struct dentry *walk; int res, is_dir, i; int locked = 0; - struct slot_info sinfo; + struct vfat_slot_info sinfo; PRINTK(("vfat_rename 1\n")); if (old_dir == new_dir && diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 0b60dd8d2850..0ea04e7431ac 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -124,6 +124,8 @@ extern void __put_user_1(void); extern void __put_user_2(void); extern void __put_user_4(void); +extern void __put_user_bad(void); + #define __put_user_x(size,ret,x,ptr) \ __asm__ __volatile__("call __put_user_" #size \ :"=a" (ret) \ @@ -141,8 +143,89 @@ extern void __put_user_4(void); __ret_pu; \ }) -#define __get_user(x,ptr) get_user(x,ptr) -#define __put_user(x,ptr) put_user(x,ptr) +#define __get_user(x,ptr) \ + __get_user_nocheck((x),(ptr),sizeof(*(ptr))) +#define __put_user(x,ptr) \ + __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) + +#define __put_user_nocheck(x,ptr,size) \ +({ \ + long __pu_err; \ + __put_user_size((x),(ptr),(size),__pu_err); \ + __pu_err; \ +}) + +#define __put_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: __put_user_asm(x,ptr,retval,"b","b","iq"); break; \ + case 2: __put_user_asm(x,ptr,retval,"w","w","ir"); break; \ + case 4: __put_user_asm(x,ptr,retval,"l","","ir"); break; \ + default: __put_user_bad(); \ + } \ +} while (0) + +struct __large_struct { unsigned long buf[100]; }; +#define __m(x) (*(struct __large_struct *)(x)) + +/* + * Tell gcc we read from memory instead of writing: this is because + * we do not write to any memory gcc knows about, so there are no + * aliasing issues. + */ +#define __put_user_asm(x, addr, err, itype, rtype, ltype) \ + __asm__ __volatile__( \ + "1: mov"itype" %"rtype"1,%2\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %3,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=r"(err) \ + : ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err)) + + +#define __get_user_nocheck(x,ptr,size) \ +({ \ + long __gu_err, __gu_val; \ + __get_user_size(__gu_val,(ptr),(size),__gu_err); \ + (x) = (__typeof__(*(ptr)))__gu_val; \ + __gu_err; \ +}) + +extern long __get_user_bad(void); + +#define __get_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: __get_user_asm(x,ptr,retval,"b","b","=q"); break; \ + case 2: __get_user_asm(x,ptr,retval,"w","w","=r"); break; \ + case 4: __get_user_asm(x,ptr,retval,"l","","=r"); break; \ + default: (x) = __get_user_bad(); \ + } \ +} while (0) + +#define __get_user_asm(x, addr, err, itype, rtype, ltype) \ + __asm__ __volatile__( \ + "1: mov"itype" %2,%"rtype"1\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %3,%0\n" \ + " xor"itype" %"rtype"1,%"rtype"1\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=r"(err), ltype (x) \ + : "m"(__m(addr)), "i"(-EFAULT), "0"(err)) /* * The "xxx_ret" versions return constant specified in third argument, if diff --git a/include/linux/dcache.h b/include/linux/dcache.h index bbb0476db02b..05bd29c4d999 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -61,6 +61,7 @@ struct dentry { struct list_head d_lru; /* d_count = 0 LRU list */ struct list_head d_child; /* child of parent list */ struct list_head d_subdirs; /* our children */ + struct list_head d_alias; /* inode alias list */ struct qstr d_name; unsigned long d_time; /* used by d_revalidate */ struct dentry_operations *d_op; diff --git a/include/linux/fs.h b/include/linux/fs.h index 97d0d77c20ed..dab098db6388 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -318,6 +318,7 @@ struct iattr { struct inode { struct list_head i_hash; struct list_head i_list; + struct list_head i_dentry; unsigned long i_ino; kdev_t i_dev; diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index c245aae26232..24b39abccf1f 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -163,7 +163,6 @@ struct msdos_dir_slot { struct vfat_slot_info { int is_long; /* was the found entry long */ - int is_alias; /* was the found entry an alias */ int long_slots; /* number of long slots in filename */ int total_slots; /* total slots (long and short) */ loff_t longname_offset; /* dir offset for longname start */ @@ -219,10 +218,10 @@ extern int fat_smap(struct inode *inode,int sector); extern int fat_free(struct inode *inode,int skip); void fat_cache_inval_inode(struct inode *inode); void fat_cache_inval_dev(kdev_t device); -extern void cache_init(void); -void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu); -void cache_add(struct inode *inode,int f_clu,int d_clu); -int get_cluster(struct inode *inode,int cluster); +extern void fat_cache_init(void); +void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu); +void fat_cache_add(struct inode *inode,int f_clu,int d_clu); +int fat_get_cluster(struct inode *inode,int cluster); /* inode.c */ extern int fat_bmap(struct inode *inode,int block); @@ -256,7 +255,7 @@ extern void fat_truncate(struct inode *inode); /* mmap.c */ extern int fat_mmap(struct file *, struct vm_area_struct *); -extern int fat_readpage(struct inode *, struct page *); +extern int fat_readpage(struct dentry *, struct page *); /* vfat.c */ diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 045815a8e4b1..aced2daeda88 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -119,6 +119,8 @@ EXPORT_SYMBOL(do_mmap); EXPORT_SYMBOL(do_munmap); EXPORT_SYMBOL(exit_mm); EXPORT_SYMBOL(exit_files); +EXPORT_SYMBOL(exit_fs); +EXPORT_SYMBOL(exit_sighand); /* internal kernel memory management */ EXPORT_SYMBOL(__get_free_pages); diff --git a/net/Config.in b/net/Config.in index c887ea466830..315306f22af9 100644 --- a/net/Config.in +++ b/net/Config.in @@ -11,6 +11,7 @@ if [ "$CONFIG_NETLINK" = "y" ]; then fi bool 'Network firewalls' CONFIG_FIREWALL bool 'Network aliasing' CONFIG_NET_ALIAS +bool 'Socket Filtering' CONFIG_FILTER tristate 'Unix domain sockets' CONFIG_UNIX bool 'TCP/IP networking' CONFIG_INET if [ "$CONFIG_INET" = "y" ]; then diff --git a/net/core/Makefile b/net/core/Makefile index dca205659a55..fc9dc31c4f72 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -16,6 +16,10 @@ ifeq ($(CONFIG_SYSCTL),y) O_OBJS += sysctl_net_core.o endif +ifdef CONFIG_FILTER +O_OBJS += filter.o +endif + ifdef CONFIG_NET O_OBJS += dev.o dev_mcast.o diff --git a/net/core/sock.c b/net/core/sock.c index 27d604ba8f3c..adf01b70b9ad 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -123,6 +123,10 @@ #include #include +#ifdef CONFIG_FILTER +#include +#endif + #define min(a,b) ((a)<(b)?(a):(b)) /* Run time adjustable parameters. */ @@ -148,6 +152,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname, struct linger ling; struct ifreq req; int ret = 0; + +#ifdef CONFIG_FILTER + struct sock_fprog fprog; +#endif /* * Options without arguments diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1414310f861a..1e4004c211ff 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1468,6 +1468,14 @@ static inline struct sock *tcp_v4_hnd_req(struct sock *sk,struct sk_buff *skb) int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) { +#ifdef CONFIG_FILTER + if (sk->filter) + { + if (sk_filter(skb, sk->filter_data, sk->filter)) + return -EPERM; /* Toss packet */ + } +#endif /* CONFIG_FILTER */ + skb_set_owner_r(skb, sk); /* diff --git a/net/netsyms.c b/net/netsyms.c index dc47a5036703..b7672f5864cc 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -121,6 +121,10 @@ EXPORT_SYMBOL(net_families); EXPORT_SYMBOL(sock_kmalloc); EXPORT_SYMBOL(sock_kfree_s); +#ifdef CONFIG_FILTER +EXPORT_SYMBOL(sk_run_filter); +#endif + EXPORT_SYMBOL(neigh_table_init); EXPORT_SYMBOL(neigh_table_clear); EXPORT_SYMBOL(__neigh_lookup); -- 2.39.5