diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Makefile | 2 | ||||
-rw-r--r-- | fs/char_dev.c | 87 | ||||
-rw-r--r-- | fs/dcache.c | 50 | ||||
-rw-r--r-- | fs/hppfs/hppfs_kern.c | 14 | ||||
-rw-r--r-- | fs/locks.c | 45 | ||||
-rw-r--r-- | fs/msdos/namei.c | 15 | ||||
-rw-r--r-- | fs/namei.c | 3 | ||||
-rw-r--r-- | fs/proc/base.c | 13 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 163 | ||||
-rw-r--r-- | fs/select.c | 8 | ||||
-rw-r--r-- | fs/sync.c | 164 | ||||
-rw-r--r-- | fs/vfat/namei.c | 18 |
12 files changed, 284 insertions, 298 deletions
diff --git a/fs/Makefile b/fs/Makefile index f3a4f7077175..83bf478e786b 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -10,7 +10,7 @@ obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \ ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \ attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \ seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \ - ioprio.o pnode.o drop_caches.o splice.o + ioprio.o pnode.o drop_caches.o splice.o sync.o obj-$(CONFIG_INOTIFY) += inotify.o obj-$(CONFIG_EPOLL) += eventpoll.o diff --git a/fs/char_dev.c b/fs/char_dev.c index 4e1b849f912f..f3418f7a6e9d 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/smp_lock.h> #include <linux/devfs_fs_kernel.h> +#include <linux/seq_file.h> #include <linux/kobject.h> #include <linux/kobj_map.h> @@ -27,8 +28,6 @@ static struct kobj_map *cdev_map; -#define MAX_PROBE_HASH 255 /* random */ - static DEFINE_MUTEX(chrdevs_lock); static struct char_device_struct { @@ -39,93 +38,29 @@ static struct char_device_struct { char name[64]; struct file_operations *fops; struct cdev *cdev; /* will die */ -} *chrdevs[MAX_PROBE_HASH]; +} *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; /* index in the above */ static inline int major_to_index(int major) { - return major % MAX_PROBE_HASH; -} - -struct chrdev_info { - int index; - struct char_device_struct *cd; -}; - -void *get_next_chrdev(void *dev) -{ - struct chrdev_info *info; - - if (dev == NULL) { - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - goto out; - info->index=0; - info->cd = chrdevs[info->index]; - if (info->cd) - goto out; - } else { - info = dev; - } - - while (info->index < ARRAY_SIZE(chrdevs)) { - if (info->cd) - info->cd = info->cd->next; - if (info->cd) - goto out; - /* - * No devices on this chain, move to the next - */ - info->index++; - info->cd = (info->index < ARRAY_SIZE(chrdevs)) ? - chrdevs[info->index] : NULL; - if (info->cd) - goto out; - } - -out: - return info; -} - -void *acquire_chrdev_list(void) -{ - mutex_lock(&chrdevs_lock); - return get_next_chrdev(NULL); -} - -void release_chrdev_list(void *dev) -{ - mutex_unlock(&chrdevs_lock); - kfree(dev); + return major % CHRDEV_MAJOR_HASH_SIZE; } +#ifdef CONFIG_PROC_FS -int count_chrdev_list(void) +void chrdev_show(struct seq_file *f, off_t offset) { struct char_device_struct *cd; - int i, count; - - count = 0; - for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) { - for (cd = chrdevs[i]; cd; cd = cd->next) - count++; + if (offset < CHRDEV_MAJOR_HASH_SIZE) { + mutex_lock(&chrdevs_lock); + for (cd = chrdevs[offset]; cd; cd = cd->next) + seq_printf(f, "%3d %s\n", cd->major, cd->name); + mutex_unlock(&chrdevs_lock); } - - return count; } -int get_chrdev_info(void *dev, int *major, char **name) -{ - struct chrdev_info *info = dev; - - if (info->cd == NULL) - return 1; - - *major = info->cd->major; - *name = info->cd->name; - return 0; -} +#endif /* CONFIG_PROC_FS */ /* * Register a single major with a specified minor range. diff --git a/fs/dcache.c b/fs/dcache.c index 19458d399502..940d188e5d14 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1101,6 +1101,32 @@ next: } /** + * d_hash_and_lookup - hash the qstr then search for a dentry + * @dir: Directory to search in + * @name: qstr of name we wish to find + * + * On hash failure or on lookup failure NULL is returned. + */ +struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) +{ + struct dentry *dentry = NULL; + + /* + * Check for a fs-specific hash function. Note that we must + * calculate the standard hash first, as the d_op->d_hash() + * routine may choose to leave the hash value unchanged. + */ + name->hash = full_name_hash(name->name, name->len); + if (dir->d_op && dir->d_op->d_hash) { + if (dir->d_op->d_hash(dir, name) < 0) + goto out; + } + dentry = d_lookup(dir, name); +out: + return dentry; +} + +/** * d_validate - verify dentry provided from insecure source * @dentry: The dentry alleged to be valid child of @dparent * @dparent: The parent dentry (known to be valid) @@ -1172,11 +1198,11 @@ void d_delete(struct dentry * dentry) spin_lock(&dentry->d_lock); isdir = S_ISDIR(dentry->d_inode->i_mode); if (atomic_read(&dentry->d_count) == 1) { - /* remove this and other inotify debug checks after 2.6.18 */ - dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED; - dentry_iput(dentry); fsnotify_nameremove(dentry, isdir); + + /* remove this and other inotify debug checks after 2.6.18 */ + dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED; return; } @@ -1616,26 +1642,12 @@ ino_t find_inode_number(struct dentry *dir, struct qstr *name) struct dentry * dentry; ino_t ino = 0; - /* - * Check for a fs-specific hash function. Note that we must - * calculate the standard hash first, as the d_op->d_hash() - * routine may choose to leave the hash value unchanged. - */ - name->hash = full_name_hash(name->name, name->len); - if (dir->d_op && dir->d_op->d_hash) - { - if (dir->d_op->d_hash(dir, name) != 0) - goto out; - } - - dentry = d_lookup(dir, name); - if (dentry) - { + dentry = d_hash_and_lookup(dir, name); + if (dentry) { if (dentry->d_inode) ino = dentry->d_inode->i_ino; dput(dentry); } -out: return ino; } diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index 2ba20cdb5baa..5e6363be246f 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -216,10 +216,10 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, static struct inode_operations hppfs_file_iops = { }; -static ssize_t read_proc(struct file *file, char *buf, ssize_t count, +static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count, loff_t *ppos, int is_user) { - ssize_t (*read)(struct file *, char *, size_t, loff_t *); + ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); ssize_t n; read = file->f_dentry->d_inode->i_fop->read; @@ -236,7 +236,7 @@ static ssize_t read_proc(struct file *file, char *buf, ssize_t count, return n; } -static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count) +static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count) { ssize_t n; int cur, err; @@ -274,7 +274,7 @@ static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count) return n; } -static ssize_t hppfs_read(struct file *file, char *buf, size_t count, +static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct hppfs_private *hppfs = file->private_data; @@ -313,12 +313,12 @@ static ssize_t hppfs_read(struct file *file, char *buf, size_t count, return(count); } -static ssize_t hppfs_write(struct file *file, const char *buf, size_t len, +static ssize_t hppfs_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct hppfs_private *data = file->private_data; struct file *proc_file = data->proc_file; - ssize_t (*write)(struct file *, const char *, size_t, loff_t *); + ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); int err; write = proc_file->f_dentry->d_inode->i_fop->write; @@ -658,7 +658,7 @@ static struct super_operations hppfs_sbops = { .statfs = hppfs_statfs, }; -static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen) +static int hppfs_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct file *proc_file; struct dentry *proc_dentry; diff --git a/fs/locks.c b/fs/locks.c index 4d9e71d43e7e..dda83d6cd48b 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -168,18 +168,9 @@ static void locks_release_private(struct file_lock *fl) /* Free a lock which is not in use. */ static void locks_free_lock(struct file_lock *fl) { - if (fl == NULL) { - BUG(); - return; - } - if (waitqueue_active(&fl->fl_wait)) - panic("Attempting to free lock with active wait queue"); - - if (!list_empty(&fl->fl_block)) - panic("Attempting to free lock with active block list"); - - if (!list_empty(&fl->fl_link)) - panic("Attempting to free lock on active lock list"); + BUG_ON(waitqueue_active(&fl->fl_wait)); + BUG_ON(!list_empty(&fl->fl_block)); + BUG_ON(!list_empty(&fl->fl_link)); locks_release_private(fl); kmem_cache_free(filelock_cache, fl); @@ -735,8 +726,9 @@ EXPORT_SYMBOL(posix_locks_deadlock); * at the head of the list, but that's secret knowledge known only to * flock_lock_file and posix_lock_file. */ -static int flock_lock_file(struct file *filp, struct file_lock *new_fl) +static int flock_lock_file(struct file *filp, struct file_lock *request) { + struct file_lock *new_fl = NULL; struct file_lock **before; struct inode * inode = filp->f_dentry->d_inode; int error = 0; @@ -751,17 +743,19 @@ static int flock_lock_file(struct file *filp, struct file_lock *new_fl) continue; if (filp != fl->fl_file) continue; - if (new_fl->fl_type == fl->fl_type) + if (request->fl_type == fl->fl_type) goto out; found = 1; locks_delete_lock(before); break; } - unlock_kernel(); - if (new_fl->fl_type == F_UNLCK) - return 0; + if (request->fl_type == F_UNLCK) + goto out; + new_fl = locks_alloc_lock(); + if (new_fl == NULL) + goto out; /* * If a higher-priority process was blocked on the old file lock, * give it the opportunity to lock the file. @@ -769,26 +763,27 @@ static int flock_lock_file(struct file *filp, struct file_lock *new_fl) if (found) cond_resched(); - lock_kernel(); for_each_lock(inode, before) { struct file_lock *fl = *before; if (IS_POSIX(fl)) break; if (IS_LEASE(fl)) continue; - if (!flock_locks_conflict(new_fl, fl)) + if (!flock_locks_conflict(request, fl)) continue; error = -EAGAIN; - if (new_fl->fl_flags & FL_SLEEP) { - locks_insert_block(fl, new_fl); - } + if (request->fl_flags & FL_SLEEP) + locks_insert_block(fl, request); goto out; } + locks_copy_lock(new_fl, request); locks_insert_lock(&inode->i_flock, new_fl); - error = 0; + new_fl = NULL; out: unlock_kernel(); + if (new_fl) + locks_free_lock(new_fl); return error; } @@ -1569,9 +1564,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) error = flock_lock_file_wait(filp, lock); out_free: - if (list_empty(&lock->fl_link)) { - locks_free_lock(lock); - } + locks_free_lock(lock); out_putf: fput(filp); diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 626a367bcd81..5b76ccd19e3f 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -12,14 +12,6 @@ #include <linux/msdos_fs.h> #include <linux/smp_lock.h> -/* MS-DOS "device special files" */ -static const unsigned char *reserved_names[] = { - "CON ", "PRN ", "NUL ", "AUX ", - "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ", - "COM1 ", "COM2 ", "COM3 ", "COM4 ", - NULL -}; - /* Characters that are undesirable in an MS-DOS file name */ static unsigned char bad_chars[] = "*?<>|\""; static unsigned char bad_if_strict_pc[] = "+=,; "; @@ -40,7 +32,6 @@ static int msdos_format_name(const unsigned char *name, int len, */ { unsigned char *walk; - const unsigned char **reserved; unsigned char c; int space; @@ -127,11 +118,7 @@ static int msdos_format_name(const unsigned char *name, int len, } while (walk - res < MSDOS_NAME) *walk++ = ' '; - if (!opts->atari) - /* GEMDOS is less stupid and has no reserved names */ - for (reserved = reserved_names; *reserved; reserved++) - if (!strncmp(res, *reserved, 8)) - return -EINVAL; + return 0; } diff --git a/fs/namei.c b/fs/namei.c index 22f6e8d16aa8..96723ae83c89 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1254,7 +1254,7 @@ out: return dentry; } -struct dentry * lookup_hash(struct nameidata *nd) +static struct dentry *lookup_hash(struct nameidata *nd) { return __lookup_hash(&nd->last, nd->dentry, nd); } @@ -2697,7 +2697,6 @@ EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ EXPORT_SYMBOL(getname); EXPORT_SYMBOL(lock_rename); -EXPORT_SYMBOL(lookup_hash); EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(page_follow_link_light); EXPORT_SYMBOL(page_put_link); diff --git a/fs/proc/base.c b/fs/proc/base.c index 8f1f49ceebec..a3a3eecef689 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -534,12 +534,15 @@ static int proc_oom_score(struct task_struct *task, char *buffer) /* If the process being read is separated by chroot from the reading process, * don't let the reader access the threads. + * + * note: this does dput(root) and mntput(vfsmnt) on exit. */ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) { struct dentry *de, *base; struct vfsmount *our_vfsmnt, *mnt; int res = 0; + read_lock(¤t->fs->lock); our_vfsmnt = mntget(current->fs->rootmnt); base = dget(current->fs->root); @@ -549,11 +552,11 @@ static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) de = root; mnt = vfsmnt; - while (vfsmnt != our_vfsmnt) { - if (vfsmnt == vfsmnt->mnt_parent) + while (mnt != our_vfsmnt) { + if (mnt == mnt->mnt_parent) goto out; - de = vfsmnt->mnt_mountpoint; - vfsmnt = vfsmnt->mnt_parent; + de = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; } if (!is_subdir(de, base)) @@ -564,7 +567,7 @@ exit: dput(base); mntput(our_vfsmnt); dput(root); - mntput(mnt); + mntput(vfsmnt); return res; out: spin_unlock(&vfsmount_lock); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index ef5a3323f4b5..5c10ea157425 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -249,144 +249,60 @@ static int cpuinfo_open(struct inode *inode, struct file *file) return seq_open(file, &cpuinfo_op); } -enum devinfo_states { - CHR_HDR, - CHR_LIST, - BLK_HDR, - BLK_LIST, - DEVINFO_DONE -}; - -struct devinfo_state { - void *chrdev; - void *blkdev; - unsigned int num_records; - unsigned int cur_record; - enum devinfo_states state; +static struct file_operations proc_cpuinfo_operations = { + .open = cpuinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, }; -static void *devinfo_start(struct seq_file *f, loff_t *pos) +static int devinfo_show(struct seq_file *f, void *v) { - struct devinfo_state *info = f->private; + int i = *(loff_t *) v; - if (*pos) { - if ((info) && (*pos <= info->num_records)) - return info; - return NULL; + if (i < CHRDEV_MAJOR_HASH_SIZE) { + if (i == 0) + seq_printf(f, "Character devices:\n"); + chrdev_show(f, i); + } else { + i -= CHRDEV_MAJOR_HASH_SIZE; + if (i == 0) + seq_printf(f, "\nBlock devices:\n"); + blkdev_show(f, i); } - info = kmalloc(sizeof(*info), GFP_KERNEL); - f->private = info; - info->chrdev = acquire_chrdev_list(); - info->blkdev = acquire_blkdev_list(); - info->state = CHR_HDR; - info->num_records = count_chrdev_list(); - info->num_records += count_blkdev_list(); - info->num_records += 2; /* Character and Block headers */ - *pos = 1; - info->cur_record = *pos; - return info; + return 0; } -static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) +static void *devinfo_start(struct seq_file *f, loff_t *pos) { - int idummy; - char *ndummy; - struct devinfo_state *info = f->private; - - switch (info->state) { - case CHR_HDR: - info->state = CHR_LIST; - (*pos)++; - /*fallthrough*/ - case CHR_LIST: - if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) { - /* - * The character dev list is complete - */ - info->state = BLK_HDR; - } else { - info->chrdev = get_next_chrdev(info->chrdev); - } - (*pos)++; - break; - case BLK_HDR: - info->state = BLK_LIST; - (*pos)++; - /*fallthrough*/ - case BLK_LIST: - if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) { - /* - * The block dev list is complete - */ - info->state = DEVINFO_DONE; - } else { - info->blkdev = get_next_blkdev(info->blkdev); - } - (*pos)++; - break; - case DEVINFO_DONE: - (*pos)++; - info->cur_record = *pos; - info = NULL; - break; - default: - break; - } - if (info) - info->cur_record = *pos; - return info; + if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) + return pos; + return NULL; } -static void devinfo_stop(struct seq_file *f, void *v) +static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) { - struct devinfo_state *info = f->private; - - if (info) { - release_chrdev_list(info->chrdev); - release_blkdev_list(info->blkdev); - f->private = NULL; - kfree(info); - } + (*pos)++; + if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) + return NULL; + return pos; } -static int devinfo_show(struct seq_file *f, void *arg) -{ - int major; - char *name; - struct devinfo_state *info = f->private; - - switch(info->state) { - case CHR_HDR: - seq_printf(f,"Character devices:\n"); - /* fallthrough */ - case CHR_LIST: - if (!get_chrdev_info(info->chrdev,&major,&name)) - seq_printf(f,"%3d %s\n",major,name); - break; - case BLK_HDR: - seq_printf(f,"\nBlock devices:\n"); - /* fallthrough */ - case BLK_LIST: - if (!get_blkdev_info(info->blkdev,&major,&name)) - seq_printf(f,"%3d %s\n",major,name); - break; - default: - break; - } - - return 0; +static void devinfo_stop(struct seq_file *f, void *v) +{ + /* Nothing to do */ } -static struct seq_operations devinfo_op = { - .start = devinfo_start, - .next = devinfo_next, - .stop = devinfo_stop, - .show = devinfo_show, +static struct seq_operations devinfo_ops = { + .start = devinfo_start, + .next = devinfo_next, + .stop = devinfo_stop, + .show = devinfo_show }; -static int devinfo_open(struct inode *inode, struct file *file) +static int devinfo_open(struct inode *inode, struct file *filp) { - return seq_open(file, &devinfo_op); + return seq_open(filp, &devinfo_ops); } static struct file_operations proc_devinfo_operations = { @@ -396,13 +312,6 @@ static struct file_operations proc_devinfo_operations = { .release = seq_release, }; -static struct file_operations proc_cpuinfo_operations = { - .open = cpuinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - extern struct seq_operations vmstat_op; static int vmstat_open(struct inode *inode, struct file *file) { diff --git a/fs/select.c b/fs/select.c index b3a3a1326af6..071660fa7b01 100644 --- a/fs/select.c +++ b/fs/select.c @@ -314,7 +314,7 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, int ret, size, max_fdset; struct fdtable *fdt; /* Allocate small arguments on the stack to save memory and be faster */ - char stack_fds[SELECT_STACK_ALLOC]; + long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; ret = -EINVAL; if (n < 0) @@ -639,8 +639,10 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) struct poll_list *walk; struct fdtable *fdt; int max_fdset; - /* Allocate small arguments on the stack to save memory and be faster */ - char stack_pps[POLL_STACK_ALLOC]; + /* Allocate small arguments on the stack to save memory and be + faster - use long to make sure the buffer is aligned properly + on 64 bit archs to avoid unaligned access */ + long stack_pps[POLL_STACK_ALLOC/sizeof(long)]; struct poll_list *stack_pp = NULL; /* Do a sanity check on nfds ... */ diff --git a/fs/sync.c b/fs/sync.c new file mode 100644 index 000000000000..8616006d2094 --- /dev/null +++ b/fs/sync.c @@ -0,0 +1,164 @@ +/* + * High-level sync()-related operations + */ + +#include <linux/kernel.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/writeback.h> +#include <linux/syscalls.h> +#include <linux/linkage.h> +#include <linux/pagemap.h> + +#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ + SYNC_FILE_RANGE_WAIT_AFTER) + +/* + * sys_sync_file_range() permits finely controlled syncing over a segment of + * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is + * zero then sys_sync_file_range() will operate from offset out to EOF. + * + * The flag bits are: + * + * SYNC_FILE_RANGE_WAIT_BEFORE: wait upon writeout of all pages in the range + * before performing the write. + * + * SYNC_FILE_RANGE_WRITE: initiate writeout of all those dirty pages in the + * range which are not presently under writeback. + * + * SYNC_FILE_RANGE_WAIT_AFTER: wait upon writeout of all pages in the range + * after performing the write. + * + * Useful combinations of the flag bits are: + * + * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE: ensures that all pages + * in the range which were dirty on entry to sys_sync_file_range() are placed + * under writeout. This is a start-write-for-data-integrity operation. + * + * SYNC_FILE_RANGE_WRITE: start writeout of all dirty pages in the range which + * are not presently under writeout. This is an asynchronous flush-to-disk + * operation. Not suitable for data integrity operations. + * + * SYNC_FILE_RANGE_WAIT_BEFORE (or SYNC_FILE_RANGE_WAIT_AFTER): wait for + * completion of writeout of all pages in the range. This will be used after an + * earlier SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE operation to wait + * for that operation to complete and to return the result. + * + * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER: + * a traditional sync() operation. This is a write-for-data-integrity operation + * which will ensure that all pages in the range which were dirty on entry to + * sys_sync_file_range() are committed to disk. + * + * + * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any + * I/O errors or ENOSPC conditions and will return those to the caller, after + * clearing the EIO and ENOSPC flags in the address_space. + * + * It should be noted that none of these operations write out the file's + * metadata. So unless the application is strictly performing overwrites of + * already-instantiated disk blocks, there are no guarantees here that the data + * will be available after a crash. + */ +asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, + int flags) +{ + int ret; + struct file *file; + loff_t endbyte; /* inclusive */ + int fput_needed; + umode_t i_mode; + + ret = -EINVAL; + if (flags & ~VALID_FLAGS) + goto out; + + endbyte = offset + nbytes; + + if ((s64)offset < 0) + goto out; + if ((s64)endbyte < 0) + goto out; + if (endbyte < offset) + goto out; + + if (sizeof(pgoff_t) == 4) { + if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { + /* + * The range starts outside a 32 bit machine's + * pagecache addressing capabilities. Let it "succeed" + */ + ret = 0; + goto out; + } + if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { + /* + * Out to EOF + */ + nbytes = 0; + } + } + + if (nbytes == 0) + endbyte = -1; + else + endbyte--; /* inclusive */ + + ret = -EBADF; + file = fget_light(fd, &fput_needed); + if (!file) + goto out; + + i_mode = file->f_dentry->d_inode->i_mode; + ret = -ESPIPE; + if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && + !S_ISLNK(i_mode)) + goto out_put; + + ret = do_sync_file_range(file, offset, endbyte, flags); +out_put: + fput_light(file, fput_needed); +out: + return ret; +} + +/* + * `endbyte' is inclusive + */ +int do_sync_file_range(struct file *file, loff_t offset, loff_t endbyte, + int flags) +{ + int ret; + struct address_space *mapping; + + mapping = file->f_mapping; + if (!mapping) { + ret = -EINVAL; + goto out; + } + + ret = 0; + if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) { + ret = wait_on_page_writeback_range(mapping, + offset >> PAGE_CACHE_SHIFT, + endbyte >> PAGE_CACHE_SHIFT); + if (ret < 0) + goto out; + } + + if (flags & SYNC_FILE_RANGE_WRITE) { + ret = __filemap_fdatawrite_range(mapping, offset, endbyte, + WB_SYNC_NONE); + if (ret < 0) + goto out; + } + + if (flags & SYNC_FILE_RANGE_WAIT_AFTER) { + ret = wait_on_page_writeback_range(mapping, + offset >> PAGE_CACHE_SHIFT, + endbyte >> PAGE_CACHE_SHIFT); + } +out: + return ret; +} +EXPORT_SYMBOL_GPL(do_sync_file_range); diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index ef46939c0c1a..a56cec3be5f0 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -185,24 +185,6 @@ static int vfat_valid_longname(const unsigned char *name, unsigned int len) return -EINVAL; if (len >= 256) return -ENAMETOOLONG; - - /* MS-DOS "device special files" */ - if (len == 3 || (len > 3 && name[3] == '.')) { /* basename == 3 */ - if (!strnicmp(name, "aux", 3) || - !strnicmp(name, "con", 3) || - !strnicmp(name, "nul", 3) || - !strnicmp(name, "prn", 3)) - return -EINVAL; - } - if (len == 4 || (len > 4 && name[4] == '.')) { /* basename == 4 */ - /* "com1", "com2", ... */ - if ('1' <= name[3] && name[3] <= '9') { - if (!strnicmp(name, "com", 3) || - !strnicmp(name, "lpt", 3)) - return -EINVAL; - } - } - return 0; } |