From 89eba5eb77bbf92ffed6686c951cc35f4027e71f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 27 Jul 2000 23:20:03 +0000 Subject: Merge with Linux 2.4.0-test5-pre5. --- fs/buffer.c | 9 +++--- fs/devfs/base.c | 16 +++++++-- fs/devices.c | 89 ++++++++++++++++++++++++++------------------------- fs/dquot.c | 2 +- fs/ext2/inode.c | 5 ++- fs/fcntl.c | 69 +++++++++++++++++++++++++++++---------- fs/nfsd/auth.c | 7 ++-- fs/nfsd/nfsctl.c | 4 --- fs/nfsd/vfs.c | 33 ------------------- fs/partitions/check.c | 1 - fs/proc/proc_misc.c | 23 +++++++------ fs/select.c | 2 +- fs/super.c | 27 ++++++++++++---- fs/vfat/namei.c | 7 ++-- 14 files changed, 163 insertions(+), 131 deletions(-) (limited to 'fs') diff --git a/fs/buffer.c b/fs/buffer.c index 20790847f..8b5d19bda 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -708,11 +708,11 @@ static void refill_freelist(int size) } } -void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *dev_id) +void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private) { bh->b_list = BUF_CLEAN; bh->b_end_io = handler; - bh->b_dev_id = dev_id; + bh->b_private = private; } static void end_buffer_io_sync(struct buffer_head *bh, int uptodate) @@ -1742,7 +1742,7 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate) mark_buffer_uptodate(bh, uptodate); - kiobuf = bh->b_kiobuf; + kiobuf = bh->b_private; unlock_buffer(bh); end_kio_request(kiobuf, uptodate); } @@ -1862,11 +1862,10 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], set_bh_page(tmp, map, offset); tmp->b_this_page = tmp; - init_buffer(tmp, end_buffer_io_kiobuf, NULL); + init_buffer(tmp, end_buffer_io_kiobuf, iobuf); tmp->b_dev = dev; tmp->b_blocknr = blocknr; tmp->b_state = 1 << BH_Mapped; - tmp->b_kiobuf = iobuf; if (rw == WRITE) { set_bit(BH_Uptodate, &tmp->b_state); diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 38a773d72..ad28db63a 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -1246,8 +1246,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, } if (ops == NULL) { - if ( S_ISCHR (mode) ) ops = get_chrfops (major, 0); - else if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major); + if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major); if (ops == NULL) { printk ("%s: devfs_register(%s): NULL ops pointer\n", @@ -2506,6 +2505,19 @@ static int devfs_open (struct inode *inode, struct file *file) else { /* Fallback to legacy scheme */ + /* + * Do we need it? Richard, could you verify it? + * It can legitimately happen if + * it is a character device and + * df->ops == NULL and + * de->registered is true, + * but AFAICS it can't happen - in devfs_register() we never set + * ->ops to NULL, in unregister() we set ->registered to false, + * in devfs_mknod() we set it to NULL only if ->register is false. + * + * Looks like this fallback is not needed at all. + * AV + */ if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file); else err = -ENODEV; } diff --git a/fs/devices.c b/fs/devices.c index 3023747da..dd7db7730 100644 --- a/fs/devices.c +++ b/fs/devices.c @@ -35,6 +35,7 @@ struct device_struct { struct file_operations * fops; }; +static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED; static struct device_struct chrdevs[MAX_CHRDEV] = { { NULL, NULL }, }; @@ -47,11 +48,13 @@ int get_device_list(char * page) int len; len = sprintf(page, "Character devices:\n"); + read_lock(&chrdevs_lock); for (i = 0; i < MAX_CHRDEV ; i++) { if (chrdevs[i].fops) { len += sprintf(page+len, "%3d %s\n", i, chrdevs[i].name); } } + read_unlock(&chrdevs_lock); len += get_blkdev_list(page+len); return len; } @@ -59,68 +62,66 @@ int get_device_list(char * page) /* Return the function table of a device. Load the driver if needed. + Increment the reference count of module in question. */ -static struct file_operations * get_fops( - unsigned int major, - unsigned int minor, - unsigned int maxdev, - const char *mangle, /* String to use to build the module name */ - struct device_struct tb[]) +static struct file_operations * get_chrfops(unsigned int major, unsigned int minor) { struct file_operations *ret = NULL; - if (major < maxdev){ + if (!major || major >= MAX_CHRDEV) + return NULL; + + read_lock(&chrdevs_lock); + ret = fops_get(chrdevs[major].fops); + read_unlock(&chrdevs_lock); #ifdef CONFIG_KMOD - /* - * I do get request for device 0. I have no idea why. It happen - * at shutdown time for one. Without the following test, the - * kernel will happily trigger a request_module() which will - * trigger kmod and modprobe for nothing (since there - * is no device with major number == 0. And furthermore - * it locks the reboot process :-( - * - * Jacques Gelinas (jacques@solucorp.qc.ca) - * - * A. Haritsis : fix for serial module - * though we need the minor here to check if serial dev, - * we pass only the normal major char dev to kmod - * as there is no other loadable dev on these majors - */ - if ((isa_tty_dev(major) && need_serial(major,minor)) || - (major != 0 && !tb[major].fops)) { - char name[20]; - sprintf(name, mangle, major); - request_module(name); + if (ret && isa_tty_dev(major)) { + lock_kernel(); + if (need_serial(major,minor)) { + /* Force request_module anyway, but what for? */ + fops_put(ret); + ret = NULL; } -#endif - ret = tb[major].fops; + unlock_kernel(); } - return ret; -} + if (!ret) { + char name[20]; + sprintf(name, "char-major-%d", major); + request_module(name); + } + read_lock(&chrdevs_lock); + ret = fops_get(chrdevs[major].fops); + read_unlock(&chrdevs_lock); -struct file_operations * get_chrfops(unsigned int major, unsigned int minor) -{ - return get_fops (major,minor,MAX_CHRDEV,"char-major-%d",chrdevs); +#endif + return ret; } int register_chrdev(unsigned int major, const char * name, struct file_operations *fops) { if (major == 0) { + write_lock(&chrdevs_lock); for (major = MAX_CHRDEV-1; major > 0; major--) { if (chrdevs[major].fops == NULL) { chrdevs[major].name = name; chrdevs[major].fops = fops; + write_unlock(&chrdevs_lock); return major; } } + write_unlock(&chrdevs_lock); return -EBUSY; } if (major >= MAX_CHRDEV) return -EINVAL; - if (chrdevs[major].fops && chrdevs[major].fops != fops) + write_lock(&chrdevs_lock); + if (chrdevs[major].fops && chrdevs[major].fops != fops) { + write_unlock(&chrdevs_lock); return -EBUSY; + } chrdevs[major].name = name; chrdevs[major].fops = fops; + write_unlock(&chrdevs_lock); return 0; } @@ -128,12 +129,14 @@ int unregister_chrdev(unsigned int major, const char * name) { if (major >= MAX_CHRDEV) return -EINVAL; - if (!chrdevs[major].fops) - return -EINVAL; - if (strcmp(chrdevs[major].name, name)) + write_lock(&chrdevs_lock); + if (!chrdevs[major].fops || strcmp(chrdevs[major].name, name)) { + write_unlock(&chrdevs_lock); return -EINVAL; + } chrdevs[major].name = NULL; chrdevs[major].fops = NULL; + write_unlock(&chrdevs_lock); return 0; } @@ -144,15 +147,15 @@ int chrdev_open(struct inode * inode, struct file * filp) { int ret = -ENODEV; - lock_kernel(); - filp->f_op = fops_get(get_chrfops(MAJOR(inode->i_rdev), - MINOR(inode->i_rdev))); + filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); if (filp->f_op) { ret = 0; - if (filp->f_op->open != NULL) + if (filp->f_op->open != NULL) { + lock_kernel(); ret = filp->f_op->open(inode,filp); + unlock_kernel(); + } } - unlock_kernel(); return ret; } diff --git a/fs/dquot.c b/fs/dquot.c index 022dd3423..42d91c35f 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -732,7 +732,7 @@ put_it: /* Free list of dquots - called from inode.c */ void put_dquot_list(struct list_head *tofree_head) { - struct list_head *act_head = tofree_head; + struct list_head *act_head = tofree_head.next; struct dquot *dquot; /* So now we have dquots on the list... Just free them */ diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 5792d7b95..70e806b02 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -259,10 +259,9 @@ repeat: ext2_debug ("goal = %d.\n", goal); tmp = ext2_alloc_block (inode, goal, err); - if (!tmp) { - *err = -ENOSPC; + if (!tmp) return NULL; - } + if (metadata) { result = getblk (inode->i_dev, tmp, blocksize); if (!buffer_uptodate(result)) diff --git a/fs/fcntl.c b/fs/fcntl.c index 37e32a012..659821873 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -15,45 +15,80 @@ extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); +/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded, + * we may have blocked. + * + * Should be called with the files->file_lock spinlock held for write. + */ +static int expand_files(struct files_struct *files, int nr) +{ + int err, expand = 0; +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->pid, nr); +#endif + + if (nr >= files->max_fdset) { + expand = 1; + if ((err = expand_fdset(files, nr))) + goto out; + } + if (nr >= files->max_fds) { + expand = 1; + if ((err = expand_fd_array(files, nr))) + goto out; + } + err = expand; + out: +#ifdef FDSET_DEBUG + if (err) + printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err); +#endif + return err; +} + /* * locate_fd finds a free file descriptor in the open_fds fdset, * expanding the fd arrays if necessary. The files write lock will be * held on exit to ensure that the fd can be entered atomically. */ -static inline int locate_fd(struct files_struct *files, - struct file *file, int start) +static int locate_fd(struct files_struct *files, + struct file *file, int orig_start) { unsigned int newfd; int error; + int start; write_lock(&files->file_lock); repeat: - error = -EMFILE; + /* + * Someone might have closed fd's in the range + * orig_start..files->next_fd + */ + start = orig_start; if (start < files->next_fd) start = files->next_fd; - if (start >= files->max_fdset) { - expand: - error = expand_files(files, start); - if (error < 0) - goto out; - goto repeat; + + newfd = start; + if (start < files->max_fdset) { + newfd = find_next_zero_bit(files->open_fds->fds_bits, + files->max_fdset, start); } - newfd = find_next_zero_bit(files->open_fds->fds_bits, - files->max_fdset, start); - error = -EMFILE; if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out; - if (newfd >= files->max_fdset) - goto expand; error = expand_files(files, newfd); if (error < 0) goto out; - if (error) /* If we might have blocked, try again. */ + + /* + * If we needed to expand the fs array we + * might have blocked - try again. + */ + if (error) goto repeat; if (start <= files->next_fd) @@ -104,8 +139,8 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) if (newfd == oldfd) goto out_unlock; err = -EBADF; - if (newfd >= NR_OPEN) - goto out_unlock; /* following POSIX.1 6.2.1 */ + if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur) + goto out_unlock; get_file(file); /* We are now finished with oldfd */ err = expand_files(files, newfd); diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 74f174d63..12fa97fe1 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -10,6 +10,7 @@ #include #include +#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) void nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) { @@ -50,10 +51,10 @@ nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) current->ngroups = i; if ((cred->cr_uid)) { - cap_t(current->cap_effective) &= ~CAP_FS_MASK; + cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; } else { - cap_t(current->cap_effective) |= (CAP_FS_MASK & - current->cap_permitted); + cap_t(current->cap_effective) |= (CAP_NFSD_MASK & + current->cap_permitted); } rqstp->rq_userset = 1; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index d3bb67b53..20e82fa7a 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -331,10 +331,6 @@ init_module(void) void cleanup_module(void) { - if (MOD_IN_USE) { - printk("nfsd: nfsd busy, remove delayed\n"); - return; - } do_nfsservctl = NULL; nfsd_export_shutdown(); nfsd_cache_shutdown(); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 2cdec3ec8..20fa7fafe 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -196,7 +196,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) int ftype = 0; int imode; int err; - kernel_cap_t saved_cap = 0; int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) @@ -283,10 +282,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) iap->ia_valid |= ATTR_CTIME; - if (current->fsuid != 0) { - saved_cap = current->cap_effective; - cap_clear(current->cap_effective); - } #ifdef CONFIG_QUOTA /* DQUOT_TRANSFER needs both ia_uid and ia_gid defined */ if (iap->ia_valid & (ATTR_UID|ATTR_GID)) { @@ -312,8 +307,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) fh_unlock(fhp); put_write_access(inode); } - if (current->fsuid != 0) - current->cap_effective = saved_cap; if (err) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) @@ -640,9 +633,6 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, mm_segment_t oldfs; int err = 0; int stable = *stablep; -#ifdef CONFIG_QUOTA - uid_t saved_euid; -#endif err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file); if (err) @@ -680,15 +670,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); -#ifdef CONFIG_QUOTA - /* This is for disk quota. */ - saved_euid = current->euid; - current->euid = current->fsuid; - err = file.f_op->write(&file, buf, cnt, &file.f_pos); - current->euid = saved_euid; -#else err = file.f_op->write(&file, buf, cnt, &file.f_pos); -#endif if (err >= 0) nfsdstats.io_write += cnt; set_fs(oldfs); @@ -696,17 +678,10 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, /* clear setuid/setgid flag after write */ if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) { struct iattr ia; - kernel_cap_t saved_cap = 0; ia.ia_valid = ATTR_MODE; ia.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID); - if (current->fsuid != 0) { - saved_cap = current->cap_effective; - cap_clear(current->cap_effective); - } notify_change(dentry, &ia); - if (current->fsuid != 0) - current->cap_effective = saved_cap; } if (err >= 0 && stable) { @@ -1463,7 +1438,6 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) { struct inode *inode = dentry->d_inode; int err; - kernel_cap_t saved_cap = 0; if (acc == MAY_NOP) return 0; @@ -1522,10 +1496,6 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) inode->i_uid == current->fsuid) return 0; - if (current->fsuid != 0) { - saved_cap = current->cap_effective; - cap_clear(current->cap_effective); - } err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); @@ -1533,9 +1503,6 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) if (err == -EACCES && S_ISREG(inode->i_mode) && acc == MAY_READ) err = permission(inode, MAY_EXEC); - if (current->fsuid != 0) - current->cap_effective = saved_cap; - return err? nfserrno(err) : 0; } diff --git a/fs/partitions/check.c b/fs/partitions/check.c index a72e2ccbc..29b93e5a5 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -34,7 +34,6 @@ #include "ultrix.h" extern void device_init(void); -extern void md_run_setup(void); extern int *blk_size[]; extern void rd_load(void); extern void initrd_load(void); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 9f574e278..d7aabc334 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -287,18 +287,21 @@ static int kstat_read_proc(char *page, char **start, off_t off, int i, len; extern unsigned long total_forks; unsigned long jif = hz_to_std(jiffies); - unsigned sum = 0; + unsigned int sum = 0, user = 0, nice = 0, system = 0; int major, disk; - for (i = 0 ; i < NR_IRQS ; i++) - sum += kstat_irqs(i); - - len = sprintf(page, - "cpu %u %u %u %lu\n", - hz_to_std(kstat.cpu_user), - hz_to_std(kstat.cpu_nice), - hz_to_std(kstat.cpu_system), - jif*smp_num_cpus - hz_to_std(kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system)); + for (i = 0 ; i < smp_num_cpus; i++) { + int cpu = cpu_logical_map(i), j; + + user += hz_to_std(kstat.per_cpu_user[cpu]); + nice += hz_to_std(kstat.per_cpu_nice[cpu]); + system += hz_to_std(kstat.per_cpu_system[cpu]); + for (j = 0 ; j < NR_IRQS ; j++) + sum += kstat.irqs[cpu][j]; + } + + len = sprintf(page, "cpu %u %u %u %lu\n", user, nice, system, + jif * smp_num_cpus - (user + nice + system)); for (i = 0 ; i < smp_num_cpus; i++) len += sprintf(page + len, "cpu%d %u %u %u %lu\n", i, diff --git a/fs/select.c b/fs/select.c index 0b3718309..a49213ecb 100644 --- a/fs/select.c +++ b/fs/select.c @@ -37,7 +37,7 @@ struct poll_table_page { }; #define POLL_TABLE_FULL(table) \ - ((unsigned long)(table->entry+1) > PAGE_SIZE + (unsigned long)(table)) + ((unsigned long)((table)->entry+1) > PAGE_SIZE + (unsigned long)(table)) /* * Ok, Peter made a complicated, but straightforward multiple_wait() function. diff --git a/fs/super.c b/fs/super.c index 3303789f6..91e17f2b6 100644 --- a/fs/super.c +++ b/fs/super.c @@ -285,7 +285,7 @@ static LIST_HEAD(vfsmntlist); * add_vfsmnt - add a new mount node * @nd: location of mountpoint or %NULL if we want a root node * @root: root of (sub)tree to be mounted - * @dev_name: device name to show in /proc/mounts + * @dev_name: device name to show in /proc/mounts or %NULL (for "none"). * * This is VFS idea of mount. New node is allocated, bound to a tree * we are mounting and optionally (OK, usually) registered as mounted @@ -295,6 +295,13 @@ static LIST_HEAD(vfsmntlist); * Potential reason for failure (aside of trivial lack of memory) is a * deleted mountpoint. Caller must hold ->i_zombie on mountpoint * dentry (if any). + * + * Node is marked as MNT_VISIBLE (visible in /proc/mounts) unless both + * @nd and @devname are %NULL. It works since we pass non-%NULL @devname + * when we are mounting root and kern_mount() filesystems are deviceless. + * If we will get a kern_mount() filesystem with nontrivial @devname we + * will have to pass the visibility flag explicitly, so if we will add + * support for such beasts we'll have to change prototype. */ static struct vfsmount *add_vfsmnt(struct nameidata *nd, @@ -310,6 +317,9 @@ static struct vfsmount *add_vfsmnt(struct nameidata *nd, goto out; memset(mnt, 0, sizeof(struct vfsmount)); + if (nd || dev_name) + mnt->mnt_flags = MNT_VISIBLE; + /* It may be NULL, but who cares? */ if (dev_name) { name = kmalloc(strlen(dev_name)+1, GFP_KERNEL); @@ -344,7 +354,8 @@ out: return mnt; fail: spin_unlock(&dcache_lock); - kfree(mnt->mnt_devname); + if (mnt->mnt_devname) + kfree(mnt->mnt_devname); kfree(mnt); return NULL; } @@ -370,7 +381,8 @@ static void move_vfsmnt(struct vfsmount *mnt, /* flip names */ if (new_devname) { - kfree(mnt->mnt_devname); + if (mnt->mnt_devname) + kfree(mnt->mnt_devname); mnt->mnt_devname = new_devname; } @@ -411,7 +423,8 @@ static void remove_vfsmnt(struct vfsmount *mnt) dput(mnt->mnt_mountpoint); dput(mnt->mnt_root); - kfree(mnt->mnt_devname); + if (mnt->mnt_devname) + kfree(mnt->mnt_devname); kfree(mnt); } @@ -460,11 +473,13 @@ int get_filesystem_info( char *buf ) for (p = vfsmntlist.next; p!=&vfsmntlist && len < PAGE_SIZE - 160; p = p->next) { struct vfsmount *tmp = list_entry(p, struct vfsmount, mnt_list); + if (!(tmp->mnt_flags & MNT_VISIBLE)) + continue; path = d_path(tmp->mnt_root, tmp, buffer, PAGE_SIZE); if (!path) continue; len += sprintf( buf + len, "%s %s %s %s", - tmp->mnt_devname, path, + tmp->mnt_devname ? tmp->mnt_devname : "none", path, tmp->mnt_sb->s_type->name, tmp->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw" ); for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { @@ -922,7 +937,7 @@ struct vfsmount *kern_mount(struct file_system_type *type) put_unnamed_dev(dev); return ERR_PTR(-EINVAL); } - mnt = add_vfsmnt(NULL, sb->s_root, "none"); + mnt = add_vfsmnt(NULL, sb->s_root, NULL); if (!mnt) { kill_super(sb, 0); return ERR_PTR(-ENOMEM); diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 9c38896a3..3895b0774 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -453,10 +453,11 @@ static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len) if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL; if (strchr(replace_chars,c)) return -EINVAL; if (c < ' '|| c==':') return -EINVAL; - if (c == '.') break; + if (c == '.') goto dot; space = c == ' '; } } +dot:; if (space) return -EINVAL; if (len && c != '.') { len--; @@ -464,6 +465,7 @@ static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len) if (charbuf[0] != '.') return -EINVAL; } else return -EINVAL; + c = '.'; } if (c == '.') { if (len >= 4) return -EINVAL; @@ -522,7 +524,7 @@ static int vfat_format_name(struct nls_table *nls, wchar_t *name, if (chl == 0) return -EINVAL; for (chi = 0; chi < chl; chi++){ - if (charbuf[chi] == '.') break; + if (charbuf[chi] == '.') goto dot; if (!charbuf[chi]) return -EINVAL; if (walk-res == 8) return -EINVAL; if (strchr(replace_chars,charbuf[chi])) return -EINVAL; @@ -532,6 +534,7 @@ static int vfat_format_name(struct nls_table *nls, wchar_t *name, walk++; } } +dot:; if (space) return -EINVAL; if (len >= 0) { while (walk-res < 8) *walk++ = ' '; -- cgit v1.2.3