diff options
Diffstat (limited to 'fs')
79 files changed, 1522 insertions, 2111 deletions
diff --git a/fs/Config.in b/fs/Config.in index 8bdb7a176..730afdb94 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -78,7 +78,6 @@ if [ "$CONFIG_NET" = "y" ]; then dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET dep_mbool ' Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD - dep_mbool ' Provide NFS server over TCP support (DEVELOPER-ONLY)' CONFIG_NFSD_TCP $CONFIG_NFSD $CONFIG_EXPERIMENTAL if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then define_tristate CONFIG_SUNRPC y diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h index f36495259..9e1a59ed2 100644 --- a/fs/adfs/adfs.h +++ b/fs/adfs/adfs.h @@ -73,7 +73,7 @@ int adfs_bmap(struct inode *inode, int block); #endif struct inode *adfs_iget(struct super_block *sb, struct object_info *obj); void adfs_read_inode(struct inode *inode); -void adfs_write_inode(struct inode *inode, int unused); +void adfs_write_inode(struct inode *inode); int adfs_notify_change(struct dentry *dentry, struct iattr *attr); /* map.c */ diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index 5dacc56d6..fa3655a12 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -349,7 +349,7 @@ out: * The adfs-specific inode data has already been updated by * adfs_notify_change() */ -void adfs_write_inode(struct inode *inode, int unused) +void adfs_write_inode(struct inode *inode) { struct super_block *sb = inode->i_sb; struct object_info obj; diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 84ea2adf8..1551e613c 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -191,7 +191,7 @@ affs_read_inode(struct inode *inode) } void -affs_write_inode(struct inode *inode, int unused) +affs_write_inode(struct inode *inode) { struct buffer_head *bh; struct file_end *file_end; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 5f41c53ac..2b47ab674 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -84,7 +84,7 @@ static void bfs_read_inode(struct inode * inode) brelse(bh); } -static void bfs_write_inode(struct inode * inode, int unused) +static void bfs_write_inode(struct inode * inode) { unsigned long ino = inode->i_ino; kdev_t dev = inode->i_dev; diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index bcdadf1d7..ade9091a5 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -406,7 +406,7 @@ beyond_if: regs->gp = ex.a_gpvalue; #endif start_thread(regs, ex.a_entry, current->mm->start_stack); - if (current->ptrace&PT_PTRACED) + if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); return 0; } diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index cd6a76271..9fd867d0e 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -674,8 +674,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) interpreter, &interp_load_addr); - allow_write_access(interpreter); + lock_kernel(); fput(interpreter); + unlock_kernel(); kfree(elf_interpreter); if (elf_entry == ~0UL) { @@ -754,7 +755,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) #endif start_thread(regs, elf_entry, bprm->p); - if (current->ptrace&PT_PTRACED) + if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); retval = 0; out: @@ -762,8 +763,9 @@ out: /* error cleanup */ out_free_dentry: - allow_write_access(interpreter); + lock_kernel(); fput(interpreter); + unlock_kernel(); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c index 75f0abc59..1b18094eb 100644 --- a/fs/binfmt_em86.c +++ b/fs/binfmt_em86.c @@ -43,7 +43,6 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs) } bprm->sh_bang++; /* Well, the bang-shell is implicit... */ - allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index f9c30df1b..0d44c3d4e 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -201,7 +201,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) if (!fmt) goto _ret; - allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index 3d5023e2d..dc78f8389 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -29,7 +29,6 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) */ bprm->sh_bang++; - allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; diff --git a/fs/block_dev.c b/fs/block_dev.c index 29972c8ca..c455a735d 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -313,7 +313,7 @@ ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos) * since the vma has no handle. */ -static int block_fsync(struct file *filp, struct dentry *dentry, int datasync) +static int block_fsync(struct file *filp, struct dentry *dentry) { return fsync_dev(dentry->d_inode->i_rdev); } @@ -597,8 +597,6 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind) ret = bdev->bd_op->open(fake_inode, &fake_file); if (!ret) atomic_inc(&bdev->bd_openers); - else if (!atomic_read(&bdev->bd_openers)) - bdev->bd_op = NULL; iput(fake_inode); } } @@ -619,8 +617,6 @@ int blkdev_open(struct inode * inode, struct file * filp) ret = bdev->bd_op->open(inode,filp); if (!ret) atomic_inc(&bdev->bd_openers); - else if (!atomic_read(&bdev->bd_openers)) - bdev->bd_op = NULL; } up(&bdev->bd_sem); return ret; diff --git a/fs/buffer.c b/fs/buffer.c index 432877cdd..47d690fa4 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -68,8 +68,6 @@ static char buffersize_index[65] = * lru_list_lock > hash_table_lock > free_list_lock > unused_list_lock */ -#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers) - /* * Hash table gook.. */ @@ -325,7 +323,7 @@ asmlinkage long sys_sync(void) * filp may be NULL if called via the msync of a vma. */ -int file_fsync(struct file *filp, struct dentry *dentry, int datasync) +int file_fsync(struct file *filp, struct dentry *dentry) { struct inode * inode = dentry->d_inode; struct super_block * sb; @@ -334,7 +332,7 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) lock_kernel(); /* sync the inode to buffers */ - write_inode_now(inode, 0); + write_inode_now(inode); /* sync the superblock to buffers */ sb = inode->i_sb; @@ -362,7 +360,12 @@ asmlinkage long sys_fsync(unsigned int fd) goto out; dentry = file->f_dentry; + if (!dentry) + goto out_putf; + inode = dentry->d_inode; + if (!inode) + goto out_putf; err = -EINVAL; if (!file->f_op || !file->f_op->fsync) @@ -370,7 +373,7 @@ asmlinkage long sys_fsync(unsigned int fd) /* We need to protect against concurrent writers.. */ down(&inode->i_sem); - err = file->f_op->fsync(file, dentry, 0); + err = file->f_op->fsync(file, dentry); up(&inode->i_sem); out_putf: @@ -392,14 +395,20 @@ asmlinkage long sys_fdatasync(unsigned int fd) goto out; dentry = file->f_dentry; + if (!dentry) + goto out_putf; + inode = dentry->d_inode; + if (!inode) + goto out_putf; err = -EINVAL; if (!file->f_op || !file->f_op->fsync) goto out_putf; + /* this needs further work, at the moment it is identical to fsync() */ down(&inode->i_sem); - err = file->f_op->fsync(file, dentry, 1); + err = file->f_op->fsync(file, dentry); up(&inode->i_sem); out_putf: @@ -526,7 +535,8 @@ static void put_last_free(struct buffer_head * bh) * As we don't lock buffers (unless we are reading them, that is), * something might happen to it while we sleep (ie a read-error * will force it bad). This shouldn't really happen currently, but - * the code is ready. */ + * the code is ready. + */ struct buffer_head * get_hash_table(kdev_t dev, int block, int size) { struct buffer_head **head = &hash(dev, block); @@ -564,42 +574,6 @@ unsigned int get_hardblocksize(kdev_t dev) return 0; } -void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode) -{ - spin_lock(&lru_list_lock); - if (bh->b_inode) - list_del(&bh->b_inode_buffers); - bh->b_inode = inode; - list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers); - spin_unlock(&lru_list_lock); -} - -/* The caller must have the lru_list lock before calling the - remove_inode_queue functions. */ -static void __remove_inode_queue(struct buffer_head *bh) -{ - bh->b_inode = NULL; - list_del(&bh->b_inode_buffers); -} - -static inline void remove_inode_queue(struct buffer_head *bh) -{ - if (bh->b_inode) - __remove_inode_queue(bh); -} - -int inode_has_buffers(struct inode *inode) -{ - int ret; - - spin_lock(&lru_list_lock); - ret = !list_empty(&inode->i_dirty_buffers); - spin_unlock(&lru_list_lock); - - return ret; -} - - /* If invalidate_buffers() will trash dirty buffers, it means some kind of fs corruption is going on. Trashing dirty data always imply losing information that was supposed to be just stored on the physical layer @@ -827,137 +801,6 @@ still_busy: return; } - -/* - * Synchronise all the inode's dirty buffers to the disk. - * - * We have conflicting pressures: we want to make sure that all - * initially dirty buffers get waited on, but that any subsequently - * dirtied buffers don't. After all, we don't want fsync to last - * forever if somebody is actively writing to the file. - * - * Do this in two main stages: first we copy dirty buffers to a - * temporary inode list, queueing the writes as we go. Then we clean - * up, waiting for those writes to complete. - * - * During this second stage, any subsequent updates to the file may end - * up refiling the buffer on the original inode's dirty list again, so - * there is a chance we will end up with a buffer queued for write but - * not yet completed on that list. So, as a final cleanup we go through - * the osync code to catch these locked, dirty buffers without requeuing - * any newly dirty buffers for write. - */ - -int fsync_inode_buffers(struct inode *inode) -{ - struct buffer_head *bh; - struct inode tmp; - int err = 0, err2; - - INIT_LIST_HEAD(&tmp.i_dirty_buffers); - - spin_lock(&lru_list_lock); - - while (!list_empty(&inode->i_dirty_buffers)) { - bh = BH_ENTRY(inode->i_dirty_buffers.next); - list_del(&bh->b_inode_buffers); - if (!buffer_dirty(bh) && !buffer_locked(bh)) - bh->b_inode = NULL; - else { - bh->b_inode = &tmp; - list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers); - atomic_inc(&bh->b_count); - if (buffer_dirty(bh)) { - spin_unlock(&lru_list_lock); - ll_rw_block(WRITE, 1, &bh); - spin_lock(&lru_list_lock); - } - } - } - - while (!list_empty(&tmp.i_dirty_buffers)) { - bh = BH_ENTRY(tmp.i_dirty_buffers.prev); - remove_inode_queue(bh); - spin_unlock(&lru_list_lock); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - err = -EIO; - brelse(bh); - spin_lock(&lru_list_lock); - } - - spin_unlock(&lru_list_lock); - err2 = osync_inode_buffers(inode); - - if (err) - return err; - else - return err2; -} - - -/* - * osync is designed to support O_SYNC io. It waits synchronously for - * all already-submitted IO to complete, but does not queue any new - * writes to the disk. - * - * To do O_SYNC writes, just queue the buffer writes with ll_rw_block as - * you dirty the buffers, and then use osync_inode_buffers to wait for - * completion. Any other dirty buffers which are not yet queued for - * write will not be flushed to disk by the osync. - */ - -int osync_inode_buffers(struct inode *inode) -{ - struct buffer_head *bh; - struct list_head *list; - int err = 0; - - spin_lock(&lru_list_lock); - - repeat: - - for (list = inode->i_dirty_buffers.prev; - bh = BH_ENTRY(list), list != &inode->i_dirty_buffers; - list = bh->b_inode_buffers.prev) { - if (buffer_locked(bh)) { - atomic_inc(&bh->b_count); - spin_unlock(&lru_list_lock); - wait_on_buffer(bh); - brelse(bh); - if (!buffer_uptodate(bh)) - err = -EIO; - spin_lock(&lru_list_lock); - goto repeat; - } - } - - spin_unlock(&lru_list_lock); - return err; -} - - -/* - * Invalidate any and all dirty buffers on a given inode. We are - * probably unmounting the fs, but that doesn't mean we have already - * done a sync(). Just drop the buffers from the inode list. - */ - -void invalidate_inode_buffers(struct inode *inode) -{ - struct list_head *list, *next; - - spin_lock(&lru_list_lock); - list = inode->i_dirty_buffers.next; - while (list != &inode->i_dirty_buffers) { - next = list->next; - remove_inode_queue(BH_ENTRY(list)); - list = next; - } - spin_unlock(&lru_list_lock); -} - - /* * Ok, this is getblk, and it isn't very clear, again to hinder * race-conditions. Most of the code is seldom used, (ie repeating), @@ -1089,8 +932,6 @@ static void __refile_buffer(struct buffer_head *bh) __remove_from_lru_list(bh, bh->b_list); bh->b_list = dispose; __insert_into_lru_list(bh, dispose); - if (dispose == BUF_CLEAN) - remove_inode_queue(bh); } } @@ -1127,7 +968,6 @@ void __bforget(struct buffer_head * buf) if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf)) goto in_use; __hash_unlink(buf); - remove_inode_queue(buf); write_unlock(&hash_table_lock); __remove_from_lru_list(buf, buf->b_list); spin_unlock(&lru_list_lock); @@ -1228,8 +1068,6 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize, */ static __inline__ void __put_unused_buffer_head(struct buffer_head * bh) { - if (bh->b_inode) - BUG(); if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) { kmem_cache_free(bh_cachep, bh); } else { @@ -1443,46 +1281,6 @@ static void unmap_buffer(struct buffer_head * bh) } } -/** - * discard_buffer - discard that buffer without doing any IO - * @bh: buffer to discard - * - * This function removes a buffer from all the queues, without doing - * any IO, we are not interested in the contents of the buffer. This - * function can block if the buffer is locked. - */ -static inline struct buffer_head *discard_buffer(struct buffer_head * bh) -{ - struct buffer_head *next; - - if (bh->b_dev == B_FREE) - BUG(); - - next = bh->b_this_page; - - unmap_buffer(bh); - - spin_lock(&lru_list_lock); - write_lock(&hash_table_lock); - spin_lock(&unused_list_lock); - - if (atomic_read(&bh->b_count)) - BUG(); - - __hash_unlink(bh); - write_unlock(&hash_table_lock); - - remove_inode_queue(bh); - __remove_from_lru_list(bh, bh->b_list); - spin_unlock(&lru_list_lock); - - __put_unused_buffer_head(bh); - spin_unlock(&unused_list_lock); - - return next; -} - - /* * We don't have to release all buffers here, but * we have to be sure that no dirty buffer is left @@ -1515,43 +1313,24 @@ int block_flushpage(struct page *page, unsigned long offset) bh = next; } while (bh != head); - return 1; -} - -/** - * block_destroy_buffers - Will destroy the contents of all the - * buffers in this page - * @page: page to examine the buffers - * - * This function destroy all the buffers in one page without making - * any IO. The function can block due to the fact that discad_bufferr - * can block. - */ -void block_destroy_buffers(struct page *page) -{ - struct buffer_head *bh, *head; - - if (!PageLocked(page)) - BUG(); - if (!page->buffers) - return; - - head = page->buffers; - bh = head; - do { - /* We need to get the next buffer from discard buffer - * because discard buffer can block and anybody else - * can change the buffer list under our feet. - */ - bh = discard_buffer(bh); - }while (bh != head); - - /* Wake up anyone waiting for buffer heads */ - wake_up(&buffer_wait); + /* + * subtle. We release buffer-heads only if this is + * the 'final' flushpage. We have invalidated the get_block + * cached value unconditionally, so real IO is not + * possible anymore. + * + * If the free doesn't work out, the buffers can be + * left around - they just turn into anonymous buffers + * instead. + */ + if (!offset) { + if (!try_to_free_buffers(page, 0)) { + atomic_inc(&buffermem_pages); + return 0; + } + } - /* And free the page */ - page->buffers = NULL; - page_cache_release(page); + return 1; } static void create_empty_buffers(struct page *page, struct inode *inode, unsigned long blocksize) @@ -1654,7 +1433,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page, unsigned long block; int err = 0; unsigned blocksize, bbits; - struct buffer_head *bh, *head, *wait[MAX_BUF_PER_PAGE], **wait_bh=wait; + struct buffer_head *bh, *head, *wait[2], **wait_bh=wait; char *kaddr = (char *)kmap(page); blocksize = inode->i_sb->s_blocksize; @@ -1728,7 +1507,6 @@ static int __block_commit_write(struct inode *inode, struct page *page, } else { set_bit(BH_Uptodate, &bh->b_state); if (!atomic_set_buffer_dirty(bh)) { - buffer_insert_inode_queue(bh, inode); __mark_dirty(bh, 0); need_balance_dirty = 1; } @@ -2021,7 +1799,6 @@ static int do_kio(int rw, int nr, struct buffer_head *bh[], int size) } spin_unlock(&unused_list_lock); - wake_up(&buffer_wait); return iosize; } @@ -2158,8 +1935,6 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], __put_unused_buffer_head(bh[bhind]); } spin_unlock(&unused_list_lock); - wake_up(&buffer_wait); - goto finished; } @@ -2337,12 +2112,6 @@ out: } /* - * Can the buffer be thrown out? - */ -#define BUFFER_BUSY_BITS ((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected)) -#define buffer_busy(bh) (atomic_read(&(bh)->b_count) | ((bh)->b_state & BUFFER_BUSY_BITS)) - -/* * Sync all the buffers on one page.. * * If we have old buffers that are locked, we'll @@ -2352,7 +2121,7 @@ out: * This all is required so that we can free up memory * later. */ -static int sync_page_buffers(struct buffer_head *bh, int wait) +static void sync_page_buffers(struct buffer_head *bh, int wait) { struct buffer_head * tmp = bh; @@ -2365,19 +2134,15 @@ static int sync_page_buffers(struct buffer_head *bh, int wait) } else if (buffer_dirty(p)) ll_rw_block(WRITE, 1, &p); } while (tmp != bh); - - do { - struct buffer_head *p = tmp; - tmp = tmp->b_this_page; - if (buffer_busy(p)) - return 0; - } while (tmp != bh); - - /* Success. Now try_to_free_buffers can free the page. */ - return 1; } /* + * Can the buffer be thrown out? + */ +#define BUFFER_BUSY_BITS ((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected)) +#define buffer_busy(bh) (atomic_read(&(bh)->b_count) | ((bh)->b_state & BUFFER_BUSY_BITS)) + +/* * try_to_free_buffers() checks if all the buffers on this particular page * are unused, and free's the page if so. * @@ -2393,7 +2158,6 @@ int try_to_free_buffers(struct page * page, int wait) struct buffer_head * tmp, * bh = page->buffers; int index = BUFSIZE_INDEX(bh->b_size); -again: spin_lock(&lru_list_lock); write_lock(&hash_table_lock); spin_lock(&free_list[index].lock); @@ -2415,10 +2179,8 @@ again: /* The buffer can be either on the regular * queues or on the free list.. */ - if (p->b_dev != B_FREE) { - remove_inode_queue(p); + if (p->b_dev != B_FREE) __remove_from_queues(p); - } else __remove_from_free_list(p, index); __put_unused_buffer_head(p); @@ -2441,8 +2203,7 @@ busy_buffer_page: spin_unlock(&free_list[index].lock); write_unlock(&hash_table_lock); spin_unlock(&lru_list_lock); - if (sync_page_buffers(bh, wait)) - goto again; + sync_page_buffers(bh, wait); return 0; } @@ -2738,7 +2499,7 @@ asmlinkage long sys_bdflush(int func, long data) * the syscall above, but now we launch it ourselves internally with * kernel_thread(...) directly after the first thread in init/main.c */ -int bdflush(void *sem) +int bdflush(void * unused) { struct task_struct *tsk = current; int flushed; @@ -2760,8 +2521,6 @@ int bdflush(void *sem) recalc_sigpending(tsk); spin_unlock_irq(&tsk->sigmask_lock); - up((struct semaphore *)sem); - for (;;) { CHECK_EMERGENCY_SYNC @@ -2796,7 +2555,7 @@ int bdflush(void *sem) * You don't need to change your userspace configuration since * the userspace `update` will do_exit(0) at the first sys_bdflush(). */ -int kupdate(void *sem) +int kupdate(void * unused) { struct task_struct * tsk = current; int interval; @@ -2812,8 +2571,6 @@ int kupdate(void *sem) recalc_sigpending(tsk); spin_unlock_irq(&tsk->sigmask_lock); - up((struct semaphore *)sem); - for (;;) { /* update interval */ interval = bdf_prm.b_un.interval; @@ -2847,11 +2604,8 @@ int kupdate(void *sem) static int __init bdflush_init(void) { - DECLARE_MUTEX_LOCKED(sem); - kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - down(&sem); - kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - down(&sem); + kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + kernel_thread(kupdate, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); return 0; } diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 0faf29663..e949f7986 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -55,7 +55,7 @@ static void coda_prepare_fakefile(struct inode *coda_inode, struct dentry *open_dentry); static int coda_venus_readdir(struct file *filp, void *dirent, filldir_t filldir); -int coda_fsync(struct file *, struct dentry *dentry, int); +int coda_fsync(struct file *, struct dentry *dentry); int coda_hasmknod = 0; diff --git a/fs/coda/file.c b/fs/coda/file.c index 704b4d00b..9aecd716a 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -40,7 +40,7 @@ coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos) } /* exported from this file (used for dirs) */ -int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync) +int coda_fsync(struct file *coda_file, struct dentry *coda_dentry) { struct inode *inode = coda_dentry->d_inode; struct dentry cont_dentry; @@ -60,10 +60,10 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync) cont_dentry.d_inode = (struct inode *)inode->i_mapping->host; down(&cont_dentry.d_inode->i_sem); - result = file_fsync(NULL, &cont_dentry, datasync); + result = file_fsync(NULL, &cont_dentry); up(&cont_dentry.d_inode->i_sem); - if ( !datasync && result == 0 ) { + if ( result == 0 ) { lock_kernel(); result = venus_fsync(inode->i_sb, coda_i2f(inode)); unlock_kernel(); diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 582ea7000..45025e871 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -417,7 +417,7 @@ int init_coda_psdev(void) devfs_handle = devfs_mk_dir (NULL, "coda", 4, NULL); devfs_register_series (devfs_handle, "%u", MAX_CODADEVS, DEVFS_FL_NONE, CODA_PSDEV_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR, &coda_psdev_fops, NULL); memset(&coda_upc_comm, 0, sizeof(coda_upc_comm)); memset(&coda_super_info, 0, sizeof(coda_super_info)); diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 9f1e8b06f..0d3d15177 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -451,6 +451,31 @@ Added CONFIG_DEVFS_MOUNT. Work sponsored by SGI. v0.96 + 20000608 Richard Gooch <rgooch@atnf.csiro.au> + Disabled multi-mount capability (use VFS bindings instead). + Work sponsored by SGI. + v0.97 + 20000610 Richard Gooch <rgooch@atnf.csiro.au> + Switched to FS_SINGLE to disable multi-mounts. + 20000612 Richard Gooch <rgooch@atnf.csiro.au> + Removed module support. + Removed multi-mount code. + Removed compatibility macros: VFS has changed too much. + Work sponsored by SGI. + v0.98 + 20000614 Richard Gooch <rgooch@atnf.csiro.au> + Merged devfs inode into devfs entry. + Work sponsored by SGI. + v0.99 + 20000619 Richard Gooch <rgooch@atnf.csiro.au> + Removed dead code in <devfs_register> which used to call + <free_dentries>. + Work sponsored by SGI. + v0.100 + 20000621 Richard Gooch <rgooch@atnf.csiro.au> + Changed interface to <devfs_register>. + Work sponsored by SGI. + v0.101 */ #include <linux/types.h> #include <linux/errno.h> @@ -485,29 +510,9 @@ #include <asm/bitops.h> #include <asm/atomic.h> -#define DEVFS_VERSION "0.96 (20000430)" +#define DEVFS_VERSION "0.101 (20000621)" -#ifndef DEVFS_NAME -# define DEVFS_NAME "devfs" -#endif - -/* Compatibility for 2.2.x kernel series */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)) -# define init_waitqueue_head(p) init_waitqueue(p) -# define DECLARE_WAITQUEUE(wait, p) struct wait_queue wait = {p, NULL} -typedef struct wait_queue *wait_queue_head_t; -#endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,6)) -# define D_ALLOC_ROOT(inode) d_alloc_root (inode, NULL) -#else -# define D_ALLOC_ROOT(inode) d_alloc_root (inode) -#endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)) -# define SETUP_STATIC -# define __setup(a,b) -#else -# define SETUP_STATIC static -#endif +#define DEVFS_NAME "devfs" #define INODE_TABLE_INC 250 #define FIRST_INODE 1 @@ -604,6 +609,19 @@ struct fifo_type gid_t gid; }; +struct devfs_inode /* This structure is for "persistent" inode storage */ +{ + time_t atime; + time_t mtime; + time_t ctime; + unsigned int ino; /* Inode number as seen in the VFS */ + struct dentry *dentry; + umode_t mode; + uid_t uid; + gid_t gid; + nlink_t nlink; +}; + struct devfs_entry { void *info; @@ -619,8 +637,7 @@ struct devfs_entry struct devfs_entry *next; /* Next entry in the parent directory */ struct devfs_entry *parent; /* The parent directory */ struct devfs_entry *slave; /* Another entry to unregister */ - struct devfs_inode *first_inode; - struct devfs_inode *last_inode; + struct devfs_inode inode; umode_t mode; unsigned short namelen; /* I think 64k+ filenames are a way off... */ unsigned char registered:1; @@ -634,26 +651,6 @@ struct devfs_entry /* The root of the device tree */ static struct devfs_entry *root_entry = NULL; -struct devfs_inode /* This structure is for "persistent" inode storage */ -{ - time_t atime; - time_t mtime; - time_t ctime; - unsigned int ino; /* Inode number as seen in the VFS */ - struct devfs_entry *de; - struct fs_info *fs_info; - struct devfs_inode *prev; /* This pair are used to associate a list of */ - struct devfs_inode *next; /* inodes (one per FS) for a devfs entry */ - struct dentry *dentry; -#ifdef CONFIG_DEVFS_TUNNEL - struct dentry *covered; -#endif - umode_t mode; - uid_t uid; - gid_t gid; - nlink_t nlink; -}; - struct devfsd_buf_entry { void *data; @@ -667,7 +664,7 @@ struct fs_info /* This structure is for each mounted devfs */ { unsigned int num_inodes; /* Number of inodes created */ unsigned int table_size; /* Size of the inode pointer table */ - struct devfs_inode **table; + struct devfs_entry **table; struct super_block *sb; volatile struct devfsd_buf_entry *devfsd_buffer; volatile unsigned int devfsd_buf_in; @@ -680,23 +677,15 @@ struct fs_info /* This structure is for each mounted devfs */ atomic_t devfsd_overrun_count; wait_queue_head_t devfsd_wait_queue; wait_queue_head_t revalidate_wait_queue; - struct fs_info *prev; - struct fs_info *next; - unsigned char require_explicit:1; }; -static struct fs_info *first_fs = NULL; -static struct fs_info *last_fs = NULL; +static struct fs_info fs_info; static unsigned int next_devnum_char = MIN_DEVNUM; static unsigned int next_devnum_block = MIN_DEVNUM; static const int devfsd_buf_size = PAGE_SIZE / sizeof(struct devfsd_buf_entry); #ifdef CONFIG_DEVFS_DEBUG -# ifdef MODULE -unsigned int devfs_debug = DEBUG_NONE; -# else static unsigned int devfs_debug_init __initdata = DEBUG_NONE; static unsigned int devfs_debug = DEBUG_NONE; -# endif #endif #ifdef CONFIG_DEVFS_MOUNT @@ -770,15 +759,40 @@ static struct devfs_entry *search_for_entry_in_dir (struct devfs_entry *parent, static struct devfs_entry *create_entry (struct devfs_entry *parent, const char *name,unsigned int namelen) { - struct devfs_entry *new; + struct devfs_entry *new, **table; + /* First ensure table size is enough */ + if (fs_info.num_inodes >= fs_info.table_size) + { + if ( ( table = kmalloc (sizeof *table * + (fs_info.table_size + INODE_TABLE_INC), + GFP_KERNEL) ) == NULL ) return NULL; + fs_info.table_size += INODE_TABLE_INC; +#ifdef CONFIG_DEVFS_DEBUG + if (devfs_debug & DEBUG_I_CREATE) + printk ("%s: create_entry(): grew inode table to: %u entries\n", + DEVFS_NAME, fs_info.table_size); +#endif + if (fs_info.table) + { + memcpy (table, fs_info.table, sizeof *table *fs_info.num_inodes); + kfree (fs_info.table); + } + fs_info.table = table; + } if ( name && (namelen < 1) ) namelen = strlen (name); if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL ) return NULL; + /* Magic: this will set the ctime to zero, thus subsequent lookups will + trigger the call to <update_devfs_inode_from_entry> */ memset (new, 0, sizeof *new + namelen); new->parent = parent; if (name) memcpy (new->name, name, namelen); new->namelen = namelen; + new->inode.ino = fs_info.num_inodes + FIRST_INODE; + new->inode.nlink = 1; + fs_info.table[fs_info.num_inodes] = new; + ++fs_info.num_inodes; if (parent == NULL) return new; new->prev = parent->u.dir.last; /* Insert into the parent directory's list of children */ @@ -788,6 +802,36 @@ static struct devfs_entry *create_entry (struct devfs_entry *parent, return new; } /* End Function create_entry */ +static void update_devfs_inode_from_entry (struct devfs_entry *de) +{ + if (de == NULL) return; + if ( S_ISDIR (de->mode) ) + { + de->inode.mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + de->inode.uid = 0; + de->inode.gid = 0; + } + else if ( S_ISLNK (de->mode) ) + { + de->inode.mode = S_IFLNK | S_IRUGO | S_IXUGO; + de->inode.uid = 0; + de->inode.gid = 0; + } + else if ( S_ISFIFO (de->mode) ) + { + de->inode.mode = de->mode; + de->inode.uid = de->u.fifo.uid; + de->inode.gid = de->u.fifo.gid; + } + else + { + if (de->u.fcb.auto_owner) + de->inode.mode = (de->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO; + else de->inode.mode = de->mode; + de->inode.uid = de->u.fcb.default_uid; + de->inode.gid = de->u.fcb.default_gid; + } +} /* End Function update_devfs_inode_from_entry */ /** * get_root_entry - Get the root devfs entry. @@ -804,6 +848,8 @@ static struct devfs_entry *get_root_entry (void) if ( ( root_entry = create_entry (NULL, NULL, 0) ) == NULL ) return NULL; root_entry->registered = TRUE; root_entry->mode = S_IFDIR; + /* Force an inode update, because lookup() is never done for the root */ + update_devfs_inode_from_entry (root_entry); /* And create the entry for ".devfsd" */ if ( ( new = create_entry (root_entry, ".devfsd", 0) ) == NULL ) return NULL; @@ -1002,7 +1048,7 @@ static struct devfs_entry *find_entry (devfs_handle_t dir, return find_by_dev (root_entry, major, minor, type); } /* End Function find_entry */ -static struct devfs_inode *get_devfs_inode_from_vfs_inode (struct inode *inode) +static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode) { struct fs_info *fs_info; @@ -1012,7 +1058,7 @@ static struct devfs_inode *get_devfs_inode_from_vfs_inode (struct inode *inode) if (fs_info == NULL) return NULL; if (inode->i_ino - FIRST_INODE >= fs_info->num_inodes) return NULL; return fs_info->table[inode->i_ino - FIRST_INODE]; -} /* End Function get_devfs_inode_from_vfs_inode */ +} /* End Function get_devfs_entry_from_vfs_inode */ /** @@ -1022,21 +1068,17 @@ static struct devfs_inode *get_devfs_inode_from_vfs_inode (struct inode *inode) static void free_dentries (struct devfs_entry *de) { - struct devfs_inode *di; struct dentry *dentry; - for (di = de->first_inode; di != NULL; di = di->next) + dentry = de->inode.dentry; + if (dentry != NULL) { - dentry = di->dentry; - if (dentry != NULL) - { - dget (dentry); - di->dentry = NULL; - /* Forcefully remove the inode */ - if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0; - d_drop (dentry); - dput (dentry); - } + dget (dentry); + de->inode.dentry = NULL; + /* Forcefully remove the inode */ + if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0; + d_drop (dentry); + dput (dentry); } } /* End Function free_dentries */ @@ -1155,14 +1197,9 @@ static int devfsd_notify_one (void *data, unsigned int type, umode_t mode, static void devfsd_notify (struct devfs_entry *de, unsigned int type, int wait) { - struct fs_info *fs_info; - - for (fs_info = first_fs; fs_info != NULL; fs_info = fs_info->next) - { - if (devfsd_notify_one (de, type, de->mode, current->euid, - current->egid, fs_info) && wait) - wait_for_devfsd_finished (fs_info); - } + if (devfsd_notify_one (de, type, de->mode, current->euid, + current->egid, &fs_info) && wait) + wait_for_devfsd_finished (&fs_info); } /* End Function devfsd_notify */ @@ -1171,15 +1208,10 @@ static void devfsd_notify (struct devfs_entry *de, unsigned int type, int wait) * @dir: The handle to the parent devfs directory entry. If this is %NULL the * new name is relative to the root of the devfs. * @name: The name of the entry. - * @namelen: The number of characters in @name, not including a %NULL - * terminator. If this is 0, then @name must be %NULL-terminated and the - * length is computed internally. * @flags: A set of bitwise-ORed flags (DEVFS_FL_*). * @major: The major number. Not needed for regular files. * @minor: The minor number. Not needed for regular files. * @mode: The default file mode. - * @uid: The default UID of the file. - * @guid: The default GID of the file. * @ops: The &file_operations or &block_device_operations structure. * This must not be externally deallocated. * @info: An arbitrary pointer which will be written to the @private_data @@ -1191,12 +1223,10 @@ static void devfsd_notify (struct devfs_entry *de, unsigned int type, int wait) * On failure %NULL is returned. */ -devfs_handle_t devfs_register (devfs_handle_t dir, - const char *name, unsigned int namelen, +devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, unsigned int flags, unsigned int major, unsigned int minor, - umode_t mode, uid_t uid, gid_t gid, - void *ops, void *info) + umode_t mode, void *ops, void *info) { int is_new; struct devfs_entry *de; @@ -1231,7 +1261,6 @@ devfs_handle_t devfs_register (devfs_handle_t dir, DEVFS_NAME, name); return NULL; } - if (namelen < 1) namelen = strlen (name); if ( S_ISCHR (mode) && (flags & DEVFS_FL_AUTO_DEVNUM) ) { if (next_devnum_char >= MAX_DEVNUM) @@ -1256,7 +1285,8 @@ devfs_handle_t devfs_register (devfs_handle_t dir, minor = next_devnum_block & 0xff; ++next_devnum_block; } - de = search_for_entry (dir, name, namelen, TRUE, TRUE, &is_new, FALSE); + de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new, + FALSE); if (de == NULL) { printk ("%s: devfs_register(): could not create entry: \"%s\"\n", @@ -1284,8 +1314,6 @@ devfs_handle_t devfs_register (devfs_handle_t dir, DEVFS_NAME, name); return NULL; } - /* If entry already exists free any dentries associated with it */ - if (de->registered) free_dentries (de); } de->registered = TRUE; if ( S_ISCHR (mode) || S_ISBLK (mode) ) @@ -1302,8 +1330,16 @@ devfs_handle_t devfs_register (devfs_handle_t dir, } de->info = info; de->mode = mode; - de->u.fcb.default_uid = uid; - de->u.fcb.default_gid = gid; + if (flags & DEVFS_FL_CURRENT_OWNER) + { + de->u.fcb.default_uid = current->uid; + de->u.fcb.default_gid = current->gid; + } + else + { + de->u.fcb.default_uid = 0; + de->u.fcb.default_gid = 0; + } de->registered = TRUE; de->u.fcb.ops = ops; de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE; @@ -1687,13 +1723,9 @@ int devfs_get_maj_min (devfs_handle_t de, unsigned int *major, devfs_handle_t devfs_get_handle_from_inode (struct inode *inode) { - struct devfs_inode *di; - if (!inode || !inode->i_sb) return NULL; if (inode->i_sb->s_magic != DEVFS_SUPER_MAGIC) return NULL; - di = get_devfs_inode_from_vfs_inode (inode); - if (!di) return NULL; - return di->de; + return get_devfs_entry_from_vfs_inode (inode); } /* End Function devfs_get_handle_from_inode */ @@ -1756,19 +1788,14 @@ void *devfs_get_ops (devfs_handle_t de) int devfs_set_file_size (devfs_handle_t de, unsigned long size) { - struct devfs_inode *di; - if (de == NULL) return -EINVAL; if (!de->registered) return -EINVAL; if ( !S_ISREG (de->mode) ) return -EINVAL; if (de->u.fcb.u.file.size == size) return 0; de->u.fcb.u.file.size = size; - for (di = de->first_inode; di != NULL; di = di->next) - { - if (di->dentry == NULL) continue; - if (di->dentry->d_inode == NULL) continue; - di->dentry->d_inode->i_size = size; - } + if (de->inode.dentry == NULL) return 0; + if (de->inode.dentry->d_inode == NULL) return 0; + de->inode.dentry->d_inode->i_size = size; return 0; } /* End Function devfs_set_file_size */ @@ -1974,18 +2001,16 @@ int devfs_unregister_blkdev (unsigned int major, const char *name) return unregister_blkdev (major, name); } /* End Function devfs_unregister_blkdev */ -#ifndef MODULE - /** * devfs_setup - Process kernel boot options. * @str: The boot options after the "devfs=". */ -SETUP_STATIC int __init devfs_setup (char *str) +static int __init devfs_setup (char *str) { while ( (*str != '\0') && !isspace (*str) ) { -# ifdef CONFIG_DEVFS_DEBUG +#ifdef CONFIG_DEVFS_DEBUG if (strncmp (str, "dall", 4) == 0) { devfs_debug_init |= DEBUG_ALL; @@ -2037,7 +2062,7 @@ SETUP_STATIC int __init devfs_setup (char *str) str += 8; } else -# endif /* CONFIG_DEVFS_DEBUG */ +#endif /* CONFIG_DEVFS_DEBUG */ if (strncmp (str, "show", 4) == 0) { boot_options |= OPTION_SHOW; @@ -2068,8 +2093,6 @@ SETUP_STATIC int __init devfs_setup (char *str) __setup("devfs=", devfs_setup); -#endif /* !MODULE */ - EXPORT_SYMBOL(devfs_register); EXPORT_SYMBOL(devfs_unregister); EXPORT_SYMBOL(devfs_mk_symlink); @@ -2094,101 +2117,6 @@ EXPORT_SYMBOL(devfs_register_blkdev); EXPORT_SYMBOL(devfs_unregister_chrdev); EXPORT_SYMBOL(devfs_unregister_blkdev); -#ifdef CONFIG_DEVFS_DEBUG -MODULE_PARM(devfs_debug, "i"); -#endif - -static void update_devfs_inode_from_entry (struct devfs_inode *di) -{ - if (di == NULL) return; - if (di->de == NULL) - { - printk ("%s: update_devfs_inode_from_entry(): NULL entry\n", - DEVFS_NAME); - return; - } - if ( S_ISDIR (di->de->mode) ) - { - di->mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; - di->uid = 0; - di->gid = 0; - } - else if ( S_ISLNK (di->de->mode) ) - { - di->mode = S_IFLNK | S_IRUGO | S_IXUGO; - di->uid = 0; - di->gid = 0; - } - else if ( S_ISFIFO (di->de->mode) ) - { - di->mode = di->de->mode; - di->uid = di->de->u.fifo.uid; - di->gid = di->de->u.fifo.gid; - } - else - { - if (di->de->u.fcb.auto_owner) - di->mode = (di->de->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO; - else di->mode = di->de->mode; - di->uid = di->de->u.fcb.default_uid; - di->gid = di->de->u.fcb.default_gid; - } -} /* End Function update_devfs_inode_from_entry */ - - -/** - * create_devfs_inode - Create a devfs inode entry. - * @de: The devfs entry to associate the new inode with. - * @fs_info: The FS info. - * - * Returns a pointer to the devfs inode on success, else %NULL. - */ - -static struct devfs_inode *create_devfs_inode (struct devfs_entry *de, - struct fs_info *fs_info) -{ - struct devfs_inode *di, **table; - - /* First ensure table size is enough */ - if (fs_info->num_inodes >= fs_info->table_size) - { - if ( ( table = kmalloc (sizeof *table * - (fs_info->table_size + INODE_TABLE_INC), - GFP_KERNEL) ) == NULL ) return NULL; - fs_info->table_size += INODE_TABLE_INC; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_CREATE) - printk ("%s: create_devfs_inode(): grew inode table to: %u entries\n", - DEVFS_NAME, fs_info->table_size); -#endif - if (fs_info->table) - { - memcpy (table, fs_info->table, sizeof *table *fs_info->num_inodes); - kfree (fs_info->table); - } - fs_info->table = table; - } - if ( ( di = kmalloc (sizeof *di, GFP_KERNEL) ) == NULL ) return NULL; - memset (di, 0, sizeof *di); - di->ino = fs_info->num_inodes + FIRST_INODE; - di->nlink = 1; - fs_info->table[fs_info->num_inodes] = di; - ++fs_info->num_inodes; - di->de = de; - di->fs_info = fs_info; - di->prev = de->last_inode; - if (de->first_inode == NULL) de->first_inode = di; - else de->last_inode->next = di; - de->last_inode = di; - update_devfs_inode_from_entry (di); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_CREATE) - printk ("%s: create_devfs_inode(): new di(%u): %p\n", - DEVFS_NAME, di->ino, di); -#endif - return di; -} /* End Function create_devfs_inode */ - /** * try_modload - Notify devfsd of an inode lookup. @@ -2224,34 +2152,6 @@ static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info, return 0; } /* End Function try_modload */ -static void delete_fs (struct fs_info *fs_info) -{ - unsigned int count; - struct devfs_inode *di; - struct devfs_entry *de; - - if (fs_info == NULL) return; - for (count = 0; count < fs_info->num_inodes; ++count) - { - /* Unhook this inode from the devfs tree */ - di = fs_info->table[count]; - de = di->de; - if (di->prev == NULL) de->first_inode = di->next; - else di->prev->next = di->next; - if (di->next == NULL) de->last_inode = di->prev; - else di->next->prev = di->prev; - memset (di, 0, sizeof *di); - kfree (di); - } - if (fs_info->table) kfree (fs_info->table); - if (fs_info->prev == NULL) first_fs = fs_info->next; - else fs_info->prev->next = fs_info->next; - if (fs_info->next == NULL) last_fs = fs_info->prev; - else fs_info->next->prev = fs_info->prev; - memset (fs_info, 0, sizeof *fs_info); - kfree (fs_info); -} /* End Function delete_fs */ - /** * check_disc_changed - Check if a removable disc was changed. @@ -2345,19 +2245,19 @@ static struct inode_operations devfs_symlink_iops; static void devfs_read_inode (struct inode *inode) { - struct devfs_inode *di; + struct devfs_entry *de; - di = get_devfs_inode_from_vfs_inode (inode); - if (di == NULL) + de = get_devfs_entry_from_vfs_inode (inode); + if (de == NULL) { - printk ("%s: read_inode(%d): VFS inode: %p NO devfs_inode\n", + printk ("%s: read_inode(%d): VFS inode: %p NO devfs_entry\n", DEVFS_NAME, (int) inode->i_ino, inode); return; } #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_I_READ) - printk ("%s: read_inode(%d): VFS inode: %p devfs_inode: %p\n", - DEVFS_NAME, (int) inode->i_ino, inode, di); + printk ("%s: read_inode(%d): VFS inode: %p devfs_entry: %p\n", + DEVFS_NAME, (int) inode->i_ino, inode, de); #endif inode->i_size = 0; inode->i_blocks = 0; @@ -2365,39 +2265,39 @@ static void devfs_read_inode (struct inode *inode) inode->i_op = &devfs_iops; inode->i_fop = &devfs_fops; inode->i_rdev = NODEV; - if ( S_ISCHR (di->mode) ) + if ( S_ISCHR (de->inode.mode) ) { - inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major, - di->de->u.fcb.u.device.minor); + inode->i_rdev = MKDEV (de->u.fcb.u.device.major, + de->u.fcb.u.device.minor); } - else if ( S_ISBLK (di->mode) ) + else if ( S_ISBLK (de->inode.mode) ) { - inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major, - di->de->u.fcb.u.device.minor); + inode->i_rdev = MKDEV (de->u.fcb.u.device.major, + de->u.fcb.u.device.minor); inode->i_bdev = bdget (inode->i_rdev); if (inode->i_bdev) { - if (!inode->i_bdev->bd_op && di->de->u.fcb.ops) - inode->i_bdev->bd_op = di->de->u.fcb.ops; + if (!inode->i_bdev->bd_op && de->u.fcb.ops) + inode->i_bdev->bd_op = de->u.fcb.ops; } else printk ("%s: read_inode(%d): no block device from bdget()\n", DEVFS_NAME, (int) inode->i_ino); } - else if ( S_ISFIFO (di->mode) ) inode->i_fop = &def_fifo_fops; - else if ( S_ISREG (di->mode) ) inode->i_size = di->de->u.fcb.u.file.size; - else if ( S_ISDIR (di->mode) ) inode->i_op = &devfs_dir_iops; - else if ( S_ISLNK (di->mode) ) + else if ( S_ISFIFO (de->inode.mode) ) inode->i_fop = &def_fifo_fops; + else if ( S_ISREG (de->inode.mode) ) inode->i_size = de->u.fcb.u.file.size; + else if ( S_ISDIR (de->inode.mode) ) inode->i_op = &devfs_dir_iops; + else if ( S_ISLNK (de->inode.mode) ) { inode->i_op = &devfs_symlink_iops; - inode->i_size = di->de->u.symlink.length; - } - inode->i_mode = di->mode; - inode->i_uid = di->uid; - inode->i_gid = di->gid; - inode->i_atime = di->atime; - inode->i_mtime = di->mtime; - inode->i_ctime = di->ctime; - inode->i_nlink = di->nlink; + inode->i_size = de->u.symlink.length; + } + inode->i_mode = de->inode.mode; + inode->i_uid = de->inode.uid; + inode->i_gid = de->inode.gid; + inode->i_atime = de->inode.atime; + inode->i_mtime = de->inode.mtime; + inode->i_ctime = de->inode.ctime; + inode->i_nlink = de->inode.nlink; #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_I_READ) printk ("%s: mode: 0%o uid: %d gid: %d\n", @@ -2409,7 +2309,7 @@ static void devfs_read_inode (struct inode *inode) static void devfs_write_inode (struct inode *inode, int unused) { int index; - struct devfs_inode *di; + struct devfs_entry *de; struct fs_info *fs_info = inode->i_sb->u.generic_sbp; if (inode->i_ino < FIRST_INODE) return; @@ -2420,57 +2320,43 @@ static void devfs_write_inode (struct inode *inode, int unused) DEVFS_NAME, inode->i_ino); return; } - di = fs_info->table[index]; + de = fs_info->table[index]; #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_I_WRITE) { - printk ("%s: write_inode(%d): VFS inode: %p devfs_inode: %p\n", - DEVFS_NAME, (int) inode->i_ino, inode, di); + printk ("%s: write_inode(%d): VFS inode: %p devfs_entry: %p\n", + DEVFS_NAME, (int) inode->i_ino, inode, de); printk ("%s: mode: 0%o uid: %d gid: %d\n", DEVFS_NAME, (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid); } #endif - di->mode = inode->i_mode; - di->uid = inode->i_uid; - di->gid = inode->i_gid; - di->atime = inode->i_atime; - di->mtime = inode->i_mtime; - di->ctime = inode->i_ctime; + de->inode.mode = inode->i_mode; + de->inode.uid = inode->i_uid; + de->inode.gid = inode->i_gid; + de->inode.atime = inode->i_atime; + de->inode.mtime = inode->i_mtime; + de->inode.ctime = inode->i_ctime; } /* End Function devfs_write_inode */ static int devfs_notify_change (struct dentry *dentry, struct iattr *iattr) { int retval; - struct devfs_inode *di; + struct devfs_entry *de; struct inode *inode = dentry->d_inode; struct fs_info *fs_info = inode->i_sb->u.generic_sbp; - di = get_devfs_inode_from_vfs_inode (inode); - if (di == NULL) return -ENODEV; + de = get_devfs_entry_from_vfs_inode (inode); + if (de == NULL) return -ENODEV; retval = inode_change_ok (inode, iattr); if (retval != 0) return retval; inode_setattr (inode, iattr); if ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) - devfsd_notify_one (di->de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, + devfsd_notify_one (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, inode->i_uid, inode->i_gid, fs_info); return 0; } /* End Function devfs_notify_change */ -static void devfs_put_super (struct super_block *sb) -{ - struct fs_info *fs_info = sb->u.generic_sbp; - -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_S_PUT) - printk ("%s: put_super(): devfs ptr: %p\n", DEVFS_NAME, fs_info); -#endif -#ifdef CONFIG_DEVFS_TUNNEL - dput (fs_info->table[0]->covered); -#endif - delete_fs (fs_info); -} /* End Function devfs_put_super */ - static int devfs_statfs (struct super_block *sb, struct statfs *buf) { buf->f_type = DEVFS_SUPER_MAGIC; @@ -2486,7 +2372,6 @@ static struct super_operations devfs_sops = { read_inode: devfs_read_inode, write_inode: devfs_write_inode, - put_super: devfs_put_super, statfs: devfs_statfs, }; @@ -2501,21 +2386,22 @@ static struct super_operations devfs_sops = */ static struct inode *get_vfs_inode (struct super_block *sb, - struct devfs_inode *di, + struct devfs_entry *de, struct dentry *dentry) { struct inode *inode; - if (di->dentry != NULL) + if (de->inode.dentry != NULL) { - printk ("%s: get_vfs_inode(%u): old di->dentry: %p \"%s\" new dentry: %p \"%s\"\n", - DEVFS_NAME, di->ino, di->dentry, di->dentry->d_name.name, + printk ("%s: get_vfs_inode(%u): old de->inode.dentry: %p \"%s\" new dentry: %p \"%s\"\n", + DEVFS_NAME, de->inode.ino, + de->inode.dentry, de->inode.dentry->d_name.name, dentry, dentry->d_name.name); - printk (" old inode: %p\n", di->dentry->d_inode); + printk (" old inode: %p\n", de->inode.dentry->d_inode); return NULL; } - if ( ( inode = iget (sb, di->ino) ) == NULL ) return NULL; - di->dentry = dentry; + if ( ( inode = iget (sb, de->inode.ino) ) == NULL ) return NULL; + de->inode.dentry = dentry; return inode; } /* End Function get_vfs_inode */ @@ -2533,7 +2419,6 @@ static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir) int err, count; int stored = 0; struct fs_info *fs_info; - struct devfs_inode *di; struct devfs_entry *parent, *de; struct inode *inode = file->f_dentry->d_inode; @@ -2548,8 +2433,7 @@ static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir) return -ENOTDIR; } fs_info = inode->i_sb->u.generic_sbp; - di = get_devfs_inode_from_vfs_inode (file->f_dentry->d_inode); - parent = di->de; + parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode); if ( (long) file->f_pos < 0 ) return -EINVAL; #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_F_READDIR) @@ -2579,38 +2463,13 @@ static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir) count = file->f_pos - 2; for (de = parent->u.dir.first; (de != NULL) && (count > 0); de = de->next) - { - if ( IS_HIDDEN (de) ) continue; - if (!fs_info->require_explicit) - { - --count; - continue; - } - /* Must search for an inode for this FS */ - for (di = de->first_inode; di != NULL; di = di->next) - { - if (fs_info == di->fs_info) break; - } - if (di != NULL) --count; - } + if ( !IS_HIDDEN (de) ) --count; /* Now add all remaining entries */ for (; de != NULL; de = de->next) { if ( IS_HIDDEN (de) ) continue; - /* Must search for an inode for this FS */ - for (di = de->first_inode; di != NULL; di = di->next) - { - if (fs_info == di->fs_info) break; - } - if (di == NULL) - { - if (fs_info->require_explicit) continue; - /* Have to create the inode right now to get the inum */ - di = create_devfs_inode (de, fs_info); - if (di == NULL) return -ENOMEM; - } err = (*filldir) (dirent, de->name, de->namelen, - file->f_pos, di->ino); + file->f_pos, de->inode.ino); if (err == -EINVAL) break; if (err < 0) return err; file->f_pos++; @@ -2625,16 +2484,15 @@ static int devfs_open (struct inode *inode, struct file *file) { int err; struct fcb_type *df; - struct devfs_inode *di; - struct dentry *dentry = file->f_dentry; + struct devfs_entry *de; struct fs_info *fs_info = inode->i_sb->u.generic_sbp; - di = get_devfs_inode_from_vfs_inode (inode); - if (di == NULL) return -ENODEV; - if ( S_ISDIR (di->de->mode) ) return 0; - df = &di->de->u.fcb; - if (!di->de->registered) return -ENODEV; - file->private_data = di->de->info; + de = get_devfs_entry_from_vfs_inode (inode); + if (de == NULL) return -ENODEV; + if ( S_ISDIR (de->mode) ) return 0; + df = &de->u.fcb; + if (!de->registered) return -ENODEV; + file->private_data = de->info; if ( S_ISBLK (inode->i_mode) ) { file->f_op = &def_blk_fops; @@ -2651,21 +2509,20 @@ static int devfs_open (struct inode *inode, struct file *file) } if (err < 0) return err; /* Open was successful */ - df->open = TRUE; - if (dentry->d_count != 1) return 0; /* No fancy operations */ - /* This is the first open */ + if (df->open) return 0; + df->open = TRUE; /* This is the first open */ if (df->auto_owner) { /* Change the ownership/protection */ - di->mode = (di->mode & ~S_IALLUGO) | (di->de->mode & S_IRWXUGO); - di->uid = current->euid; - di->gid = current->egid; - inode->i_mode = di->mode; - inode->i_uid = di->uid; - inode->i_gid = di->gid; + de->inode.mode = (de->inode.mode & ~S_IALLUGO) |(de->mode & S_IRWXUGO); + de->inode.uid = current->euid; + de->inode.gid = current->egid; + inode->i_mode = de->inode.mode; + inode->i_uid = de->inode.uid; + inode->i_gid = de->inode.gid; } if (df->aopen_notify) - devfsd_notify_one (di->de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode, + devfsd_notify_one (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode, current->euid, current->egid, fs_info); return 0; } /* End Function devfs_open */ @@ -2705,21 +2562,17 @@ static void devfs_d_release (struct dentry *dentry) static void devfs_d_iput (struct dentry *dentry, struct inode *inode) { - struct devfs_inode *di; + struct devfs_entry *de; - di = get_devfs_inode_from_vfs_inode (inode); + de = get_devfs_entry_from_vfs_inode (inode); #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_D_IPUT) - printk ("%s: d_iput(): dentry: %p inode: %p di: %p di->dentry: %p\n", - DEVFS_NAME, dentry, inode, di, di->dentry); + printk ("%s: d_iput(): dentry: %p inode: %p de: %p de->dentry: %p\n", + DEVFS_NAME, dentry, inode, de, de->inode.dentry); #endif - if (di->dentry == dentry) + if (de->inode.dentry == dentry) { - di->dentry = NULL; -#ifdef CONFIG_DEVFS_TUNNEL - dput (di->covered); - di->covered = NULL; -#endif + de->inode.dentry = NULL; } iput (inode); } /* End Function devfs_d_iput */ @@ -2751,7 +2604,7 @@ static struct dentry_operations devfs_wait_dops = static int devfs_d_delete (struct dentry *dentry) { struct inode *inode = dentry->d_inode; - struct devfs_inode *di; + struct devfs_entry *de; struct fs_info *fs_info; if (dentry->d_op == &devfs_wait_dops) dentry->d_op = &devfs_dops; @@ -2766,29 +2619,28 @@ static int devfs_d_delete (struct dentry *dentry) return 1; } fs_info = inode->i_sb->u.generic_sbp; - di = get_devfs_inode_from_vfs_inode (inode); + de = get_devfs_entry_from_vfs_inode (inode); #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_D_DELETE) - printk ("%s: d_delete(): dentry: %p inode: %p devfs_inode: %p\n", - DEVFS_NAME, dentry, inode, di); + printk ("%s: d_delete(): dentry: %p inode: %p devfs_entry: %p\n", + DEVFS_NAME, dentry, inode, de); #endif - if (di == NULL) return 0; - if (di->de == NULL) return 0; - if ( !S_ISCHR (di->mode) && !S_ISBLK (di->mode) && !S_ISREG (di->mode) ) + if (de == NULL) return 0; + if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) ) return 0; - if (!di->de->u.fcb.open) return 0; - di->de->u.fcb.open = FALSE; - if (di->de->u.fcb.aopen_notify) - devfsd_notify_one (di->de, DEVFSD_NOTIFY_CLOSE, inode->i_mode, + if (!de->u.fcb.open) return 0; + de->u.fcb.open = FALSE; + if (de->u.fcb.aopen_notify) + devfsd_notify_one (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode, current->euid, current->egid, fs_info); - if (!di->de->u.fcb.auto_owner) return 0; + if (!de->u.fcb.auto_owner) return 0; /* Change the ownership/protection back */ - di->mode = (di->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO; - di->uid = di->de->u.fcb.default_uid; - di->gid = di->de->u.fcb.default_gid; - inode->i_mode = di->mode; - inode->i_uid = di->uid; - inode->i_gid = di->gid; + de->inode.mode = (de->inode.mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO; + de->inode.uid = de->u.fcb.default_uid; + de->inode.gid = de->u.fcb.default_gid; + inode->i_mode = de->inode.mode; + inode->i_uid = de->inode.uid; + inode->i_gid = de->inode.gid; return 0; } /* End Function devfs_d_delete */ @@ -2802,7 +2654,6 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) { if ( !dentry->d_inode && is_devfsd_or_child (fs_info) ) { - struct devfs_inode *di = NULL; struct inode *inode; #ifdef CONFIG_DEVFS_DEBUG @@ -2816,36 +2667,27 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) printk ("%s: d_revalidate(): dentry: %p name: \"%s\" by: \"%s\"\n", DEVFS_NAME, dentry, txt, current->comm); #endif - if (de) - { - /* Search for an inode for this FS */ - for (di = de->first_inode; di != NULL; di = di->next) - if (di->fs_info == fs_info) break; - } if (de == NULL) { devfs_handle_t parent; - struct devfs_inode *pi; - pi = get_devfs_inode_from_vfs_inode (dir); - parent = pi->de; + parent = get_devfs_entry_from_vfs_inode (dir); de = search_for_entry_in_dir (parent, dentry->d_name.name, dentry->d_name.len, FALSE); } if (de == NULL) return 1; /* Create an inode, now that the driver information is available */ - if (di == NULL) di = create_devfs_inode (de, fs_info); - else if (de->no_persistence) update_devfs_inode_from_entry (di); - else if (di->ctime == 0) update_devfs_inode_from_entry (di); - else di->mode = (de->mode & ~S_IALLUGO) | (di->mode & S_IALLUGO); - if (di == NULL) return 1; - if ( ( inode = get_vfs_inode (dir->i_sb, di, dentry) ) == NULL ) + if (de->no_persistence) update_devfs_inode_from_entry (de); + else if (de->inode.ctime == 0) update_devfs_inode_from_entry (de); + else de->inode.mode = + (de->mode & ~S_IALLUGO) | (de->inode.mode & S_IALLUGO); + if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return 1; #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: d_revalidate(): new VFS inode(%u): %p devfs_inode: %p\n", - DEVFS_NAME, di->ino, inode, di); + printk ("%s: d_revalidate(): new VFS inode(%u): %p devfs_entry: %p\n", + DEVFS_NAME, de->inode.ino, inode, de); #endif d_instantiate (dentry, inode); return 1; @@ -2861,8 +2703,6 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) { struct fs_info *fs_info; - struct devfs_inode *di = NULL; - struct devfs_inode *pi; struct devfs_entry *parent, *de; struct inode *inode; char txt[STRING_LENGTH]; @@ -2887,32 +2727,13 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) #endif fs_info = dir->i_sb->u.generic_sbp; /* First try to get the devfs entry for this directory */ - pi = get_devfs_inode_from_vfs_inode (dir); - if (pi == NULL) return ERR_PTR (-EINVAL); - parent = pi->de; + parent = get_devfs_entry_from_vfs_inode (dir); + if (parent == NULL) return ERR_PTR (-EINVAL); if (!parent->registered) return ERR_PTR (-ENOENT); /* Try to reclaim an existing devfs entry */ de = search_for_entry_in_dir (parent, dentry->d_name.name, dentry->d_name.len, FALSE); - if (de) - { - /* Search for an inode for this FS */ - for (di = de->first_inode; di != NULL; di = di->next) - if (di->fs_info == fs_info) break; - } - if (fs_info->require_explicit) - { - if (di == NULL) - { - /* Make the dentry negative so a subsequent operation can deal - with it (for the benefit of mknod()). Leaving the dentry - unhashed will cause <lock_parent> to fail which in turns causes - <do_mknod> to fail */ - d_add (dentry, NULL); - return NULL; - } - } if ( ( (de == NULL) || !de->registered ) && (parent->u.dir.num_removable > 0) && get_removable_partition (parent, dentry->d_name.name, @@ -2961,17 +2782,16 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) d_add (dentry, NULL); /* Open the floodgates */ } /* Create an inode, now that the driver information is available */ - if (di == NULL) di = create_devfs_inode (de, fs_info); - else if (de->no_persistence) update_devfs_inode_from_entry (di); - else if (di->ctime == 0) update_devfs_inode_from_entry (di); - else di->mode = (de->mode & ~S_IALLUGO) | (di->mode & S_IALLUGO); - if (di == NULL) return ERR_PTR (-ENOMEM); - if ( ( inode = get_vfs_inode (dir->i_sb, di, dentry) ) == NULL ) + if (de->no_persistence) update_devfs_inode_from_entry (de); + else if (de->inode.ctime == 0) update_devfs_inode_from_entry (de); + else de->inode.mode = + (de->mode & ~S_IALLUGO) | (de->inode.mode & S_IALLUGO); + if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return ERR_PTR (-ENOMEM); #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: lookup(): new VFS inode(%u): %p devfs_inode: %p\n", - DEVFS_NAME, di->ino, inode, di); + printk ("%s: lookup(): new VFS inode(%u): %p devfs_entry: %p\n", + DEVFS_NAME, de->inode.ino, inode, de); #endif d_instantiate (dentry, inode); /* Unlock directory semaphore, which will release any waiters. They will @@ -2998,7 +2818,7 @@ static int devfs_link (struct dentry *old_dentry, struct inode *dir, static int devfs_unlink (struct inode *dir, struct dentry *dentry) { - struct devfs_inode *di; + struct devfs_entry *de; #ifdef CONFIG_DEVFS_DEBUG char txt[STRING_LENGTH]; @@ -3014,12 +2834,12 @@ static int devfs_unlink (struct inode *dir, struct dentry *dentry) if ( !dir || !S_ISDIR (dir->i_mode) ) return -ENOTDIR; if (!dentry || !dentry->d_inode) return -ENOENT; - di = get_devfs_inode_from_vfs_inode (dentry->d_inode); - if (di == NULL) return -ENOENT; - if (!di->de->registered) return -ENOENT; - di->de->registered = FALSE; - di->de->hide = TRUE; - free_dentries (di->de); + de = get_devfs_entry_from_vfs_inode (dentry->d_inode); + if (de == NULL) return -ENOENT; + if (!de->registered) return -ENOENT; + de->registered = FALSE; + de->hide = TRUE; + free_dentries (de); return 0; } /* End Function devfs_unlink */ @@ -3028,17 +2848,14 @@ static int devfs_symlink (struct inode *dir, struct dentry *dentry, { int err; struct fs_info *fs_info; - struct devfs_inode *pi; - struct devfs_inode *di = NULL; struct devfs_entry *parent, *de; struct inode *inode; if ( !dir || !S_ISDIR (dir->i_mode) ) return -ENOTDIR; fs_info = dir->i_sb->u.generic_sbp; /* First try to get the devfs entry for this directory */ - pi = get_devfs_inode_from_vfs_inode (dir); - if (pi == NULL) return -EINVAL; - parent = pi->de; + parent = get_devfs_entry_from_vfs_inode (dir); + if (parent == NULL) return -EINVAL; if (!parent->registered) return -ENOENT; err = devfs_mk_symlink (parent, dentry->d_name.name, dentry->d_name.len, DEVFS_FL_NONE, symname, 0, &de, NULL); @@ -3048,27 +2865,20 @@ static int devfs_symlink (struct inode *dir, struct dentry *dentry, DEVFS_NAME, err); #endif if (err < 0) return err; - /* Search for an inode for this FS */ - for (di = de->first_inode; di != NULL; di = di->next) - { - if (di->fs_info == fs_info) break; - } - if (di == NULL) di = create_devfs_inode (de, fs_info); - if (di == NULL) return -ENOMEM; - di->mode = de->mode; - di->atime = CURRENT_TIME; - di->mtime = CURRENT_TIME; - di->ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, di, dentry) ) == NULL ) + de->inode.mode = de->mode; + de->inode.atime = CURRENT_TIME; + de->inode.mtime = CURRENT_TIME; + de->inode.ctime = CURRENT_TIME; + if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_DISABLED) printk ("%s: symlink(): new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, di->ino, inode, dentry); + DEVFS_NAME, de->inode.ino, inode, dentry); #endif de->hide = FALSE; d_instantiate (dentry, inode); - devfsd_notify_one (di->de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, inode->i_uid, inode->i_gid, fs_info); return 0; } /* End Function devfs_symlink */ @@ -3077,8 +2887,6 @@ static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) { int is_new; struct fs_info *fs_info; - struct devfs_inode *di = NULL; - struct devfs_inode *pi; struct devfs_entry *parent, *de; struct inode *inode; @@ -3087,9 +2895,8 @@ static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) fs_info = dir->i_sb->u.generic_sbp; /* We are allowed to create the directory */ /* First try to get the devfs entry for this directory */ - pi = get_devfs_inode_from_vfs_inode (dir); - if (pi == NULL) return -EINVAL; - parent = pi->de; + parent = get_devfs_entry_from_vfs_inode (dir); + if (parent == NULL) return -EINVAL; if (!parent->registered) return -ENOENT; /* Try to reclaim an existing devfs entry, create if there isn't one */ de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len, @@ -3110,28 +2917,21 @@ static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) } de->mode = mode; de->u.dir.num_removable = 0; - /* Search for an inode for this FS */ - for (di = de->first_inode; di != NULL; di = di->next) - { - if (di->fs_info == fs_info) break; - } - if (di == NULL) di = create_devfs_inode (de, fs_info); - if (di == NULL) return -ENOMEM; - di->mode = mode; - di->uid = current->euid; - di->gid = current->egid; - di->atime = CURRENT_TIME; - di->mtime = CURRENT_TIME; - di->ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, di, dentry) ) == NULL ) + de->inode.mode = mode; + de->inode.uid = current->euid; + de->inode.gid = current->egid; + de->inode.atime = CURRENT_TIME; + de->inode.mtime = CURRENT_TIME; + de->inode.ctime = CURRENT_TIME; + if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_DISABLED) printk ("%s: mkdir(): new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, di->ino, inode, dentry); + DEVFS_NAME, de->inode.ino, inode, dentry); #endif d_instantiate (dentry, inode); - devfsd_notify_one (di->de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, inode->i_uid, inode->i_gid, fs_info); return 0; } /* End Function devfs_mkdir */ @@ -3140,7 +2940,6 @@ static int devfs_rmdir (struct inode *dir, struct dentry *dentry) { int has_children = FALSE; struct fs_info *fs_info; - struct devfs_inode *di = NULL; struct devfs_entry *de, *child; struct inode *inode = dentry->d_inode; @@ -3148,9 +2947,8 @@ static int devfs_rmdir (struct inode *dir, struct dentry *dentry) if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL; if (inode == dir) return -EPERM; fs_info = dir->i_sb->u.generic_sbp; - di = get_devfs_inode_from_vfs_inode (inode); - if (di == NULL) return -ENOENT; - de = di->de; + de = get_devfs_entry_from_vfs_inode (inode); + if (de == NULL) return -ENOENT; if (!de->registered) return -ENOENT; if ( !S_ISDIR (de->mode) ) return -ENOTDIR; for (child = de->u.dir.first; child != NULL; child = child->next) @@ -3173,8 +2971,6 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode, { int is_new; struct fs_info *fs_info; - struct devfs_inode *di = NULL; - struct devfs_inode *pi; struct devfs_entry *parent, *de; struct inode *inode; @@ -3197,9 +2993,8 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode, !S_ISSOCK (mode) ) return -EPERM; /* We are allowed to create the node */ /* First try to get the devfs entry for this directory */ - pi = get_devfs_inode_from_vfs_inode (dir); - if (pi == NULL) return -EINVAL; - parent = pi->de; + parent = get_devfs_entry_from_vfs_inode (dir); + if (parent == NULL) return -EINVAL; if (!parent->registered) return -ENOENT; /* Try to reclaim an existing devfs entry, create if there isn't one */ de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len, @@ -3230,44 +3025,37 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode, de->registered = TRUE; de->show_unreg = FALSE; de->hide = FALSE; - /* Search for an inode for this FS */ - for (di = de->first_inode; di != NULL; di = di->next) - { - if (di->fs_info == fs_info) break; - } - if (di == NULL) di = create_devfs_inode (de, fs_info); - if (di == NULL) return -ENOMEM; - di->mode = mode; - di->uid = current->euid; - di->gid = current->egid; - di->atime = CURRENT_TIME; - di->mtime = CURRENT_TIME; - di->ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, di, dentry) ) == NULL ) + de->inode.mode = mode; + de->inode.uid = current->euid; + de->inode.gid = current->egid; + de->inode.atime = CURRENT_TIME; + de->inode.mtime = CURRENT_TIME; + de->inode.ctime = CURRENT_TIME; + if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_I_MKNOD) printk ("%s: new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, di->ino, inode, dentry); + DEVFS_NAME, de->inode.ino, inode, dentry); #endif d_instantiate (dentry, inode); - devfsd_notify_one (di->de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + devfsd_notify_one (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, inode->i_uid, inode->i_gid, fs_info); return 0; } /* End Function devfs_mknod */ static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen) { - struct devfs_inode *di = get_devfs_inode_from_vfs_inode (dentry->d_inode); + struct devfs_entry *de = get_devfs_entry_from_vfs_inode (dentry->d_inode); - return vfs_readlink (dentry, buffer, buflen, di->de->u.symlink.linkname); + return vfs_readlink (dentry, buffer, buflen, de->u.symlink.linkname); } /* End Function devfs_readlink */ static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd) { - struct devfs_inode *di = get_devfs_inode_from_vfs_inode (dentry->d_inode); + struct devfs_entry *de = get_devfs_entry_from_vfs_inode (dentry->d_inode); - return vfs_follow_link (nd, di->de->u.symlink.linkname); + return vfs_follow_link (nd, de->u.symlink.linkname); } /* End Function devfs_follow_link */ static struct inode_operations devfs_iops = @@ -3303,47 +3091,22 @@ static struct inode_operations devfs_symlink_iops = static struct super_block *devfs_read_super (struct super_block *sb, void *data, int silent) { - char *aopt = data; - struct fs_info *fs_info = NULL; - struct devfs_inode *di; struct inode *root_inode = NULL; if (get_root_entry () == NULL) goto out_no_root; - if ( ( fs_info = kmalloc (sizeof *fs_info, GFP_KERNEL) ) == NULL ) - return NULL; - memset (fs_info, 0, sizeof *fs_info); - atomic_set (&fs_info->devfsd_overrun_count, 0); - init_waitqueue_head (&fs_info->devfsd_wait_queue); - init_waitqueue_head (&fs_info->revalidate_wait_queue); - fs_info->prev = last_fs; - if (first_fs == NULL) first_fs = fs_info; - else last_fs->next = fs_info; - last_fs = fs_info; - fs_info->sb = sb; - if (aopt) - { - if (strcmp (aopt, "explicit") == 0) fs_info->require_explicit = TRUE; - } - sb->u.generic_sbp = fs_info; + atomic_set (&fs_info.devfsd_overrun_count, 0); + init_waitqueue_head (&fs_info.devfsd_wait_queue); + init_waitqueue_head (&fs_info.revalidate_wait_queue); + fs_info.sb = sb; + sb->u.generic_sbp = &fs_info; sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = DEVFS_SUPER_MAGIC; sb->s_op = &devfs_sops; - di = create_devfs_inode (root_entry, fs_info); - if (di == NULL) goto out_no_root; - if (di->ino != 1) - { - printk ("%s: read_super: root inode number is: %d!\n", - DEVFS_NAME, di->ino); - goto out_no_root; - } - if ( ( root_inode = get_vfs_inode (sb, di, NULL) ) == NULL ) + if ( ( root_inode = get_vfs_inode (sb, root_entry, NULL) ) == NULL ) goto out_no_root; - sb->s_root = D_ALLOC_ROOT (root_inode); + sb->s_root = d_alloc_root (root_inode); if (!sb->s_root) goto out_no_root; -#ifdef CONFIG_DEVFS_TUNNEL - di->covered = dget (sb->s_root->d_covered); -#endif #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_DISABLED) printk ("%s: read super, made devfs ptr: %p\n", @@ -3353,13 +3116,12 @@ static struct super_block *devfs_read_super (struct super_block *sb, out_no_root: printk ("devfs_read_super: get root inode failed\n"); - delete_fs (fs_info); if (root_inode) iput (root_inode); return NULL; } /* End Function devfs_read_super */ -static DECLARE_FSTYPE (devfs_fs_type, DEVFS_NAME, devfs_read_super, 0); +static DECLARE_FSTYPE (devfs_fs_type, DEVFS_NAME, devfs_read_super, FS_SINGLE); /* File operations for devfsd follow */ @@ -3549,25 +3311,27 @@ static int devfsd_close (struct inode *inode, struct file *file) } /* End Function devfsd_close */ -#ifdef MODULE -int init_module (void) -#else int __init init_devfs_fs (void) -#endif { + int err; + printk ("%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", DEVFS_NAME, DEVFS_VERSION); -#if defined(CONFIG_DEVFS_DEBUG) && !defined(MODULE) +#ifdef CONFIG_DEVFS_DEBUG devfs_debug = devfs_debug_init; printk ("%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug); #endif -#if !defined(MODULE) printk ("%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options); -#endif - return register_filesystem (&devfs_fs_type); -} + err = register_filesystem (&devfs_fs_type); + if (!err) + { + struct vfsmount *devfs_mnt = kern_mount (&devfs_fs_type); + err = PTR_ERR (devfs_mnt); + if ( !IS_ERR (devfs_mnt) ) err = 0; + } + return err; +} /* End Function init_devfs_fs */ -#ifndef MODULE void __init mount_devfs_fs (void) { int err; @@ -3577,39 +3341,3 @@ void __init mount_devfs_fs (void) if (err == 0) printk ("Mounted devfs on /dev\n"); else printk ("Warning: unable to mount devfs, err: %d\n", err); } /* End Function mount_devfs_fs */ -#endif - -#ifdef MODULE -static void free_entry (struct devfs_entry *parent) -{ - struct devfs_entry *de, *next; - - if (parent == NULL) return; - for (de = parent->u.dir.first; de != NULL; de = next) - { - next = de->next; - if (de->first_inode != NULL) - { - printk ("%s: free_entry(): unfreed inodes!\n", DEVFS_NAME); - } - if ( S_ISDIR (de->mode) ) - { - /* Recursively free the subdirectories: this is a stack chomper */ - free_entry (de); - } - else kfree (de); - } - kfree (parent); -} /* End Function free_entry */ - -void cleanup_module (void) -{ - unregister_filesystem (&devfs_fs_type); - if (first_fs != NULL) - { - printk ("%s: cleanup_module(): still mounted mounted filesystems!\n", - DEVFS_NAME); - } - free_entry (root_entry); -} -#endif /* MODULE */ diff --git a/fs/devfs/util.c b/fs/devfs/util.c index fe4746448..6e3f2f782 100644 --- a/fs/devfs/util.c +++ b/fs/devfs/util.c @@ -28,6 +28,8 @@ Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs 20000203 Richard Gooch <rgooch@atnf.csiro.au> Changed operations pointer type to void *. + 20000621 Richard Gooch <rgooch@atnf.csiro.au> + Changed interface to <devfs_register_series>. */ #include <linux/module.h> #include <linux/init.h> @@ -134,8 +136,6 @@ EXPORT_SYMBOL(devfs_register_tape); * @major: The major number. Not needed for regular files. * @minor_start: The starting minor number. Not needed for regular files. * @mode: The default file mode. - * @uid: The default UID of the file. - * @guid: The default GID of the file. * @ops: The &file_operations or &block_device_operations structure. * This must not be externally deallocated. * @info: An arbitrary pointer which will be written to the private_data @@ -147,8 +147,7 @@ EXPORT_SYMBOL(devfs_register_tape); void devfs_register_series (devfs_handle_t dir, const char *format, unsigned int num_entries, unsigned int flags, unsigned int major, unsigned int minor_start, - umode_t mode, uid_t uid, gid_t gid, - void *ops, void *info) + umode_t mode, void *ops, void *info) { unsigned int count; char devname[128]; @@ -156,8 +155,8 @@ void devfs_register_series (devfs_handle_t dir, const char *format, for (count = 0; count < num_entries; ++count) { sprintf (devname, format, count); - devfs_register (dir, devname, 0, flags, major, minor_start + count, - mode, uid, gid, ops, info); + devfs_register (dir, devname, flags, major, minor_start + count, + mode, ops, info); } } /* End Function devfs_register_series */ EXPORT_SYMBOL(devfs_register_series); @@ -101,54 +101,37 @@ static inline void put_binfmt(struct linux_binfmt * fmt) */ asmlinkage long sys_uselib(const char * library) { + int fd, retval; struct file * file; - struct nameidata nd; - int error; - - error = user_path_walk(library, &nd); - if (error) - goto out; - - error = -EINVAL; - if (!S_ISREG(nd.dentry->d_inode->i_mode)) - goto exit; - - error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC); - if (error) - goto exit; - - lock_kernel(); - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); - unlock_kernel(); - error = PTR_ERR(file); - if (IS_ERR(file)) - goto out; - error = -ENOEXEC; - if(file->f_op && file->f_op->read) { - struct linux_binfmt * fmt; + fd = sys_open(library, 0, 0); + if (fd < 0) + return fd; + file = fget(fd); + retval = -ENOEXEC; + if (file) { + if(file->f_op && file->f_op->read) { + struct linux_binfmt * fmt; - read_lock(&binfmt_lock); - for (fmt = formats ; fmt ; fmt = fmt->next) { - if (!fmt->load_shlib) - continue; - if (!try_inc_mod_count(fmt->module)) - continue; - read_unlock(&binfmt_lock); - error = fmt->load_shlib(file); read_lock(&binfmt_lock); - put_binfmt(fmt); - if (error != -ENOEXEC) - break; + for (fmt = formats ; fmt ; fmt = fmt->next) { + if (!fmt->load_shlib) + continue; + if (!try_inc_mod_count(fmt->module)) + continue; + read_unlock(&binfmt_lock); + retval = fmt->load_shlib(file); + read_lock(&binfmt_lock); + put_binfmt(fmt); + if (retval != -ENOEXEC) + break; + } + read_unlock(&binfmt_lock); } - read_unlock(&binfmt_lock); + fput(file); } - fput(file); -out: - return error; -exit: - path_release(&nd); - goto out; + sys_close(fd); + return retval; } /* @@ -336,7 +319,6 @@ int setup_arg_pages(struct linux_binprm *bprm) struct file *open_exec(const char *name) { struct nameidata nd; - struct inode *inode; struct file *file; int err = 0; @@ -346,22 +328,14 @@ struct file *open_exec(const char *name) unlock_kernel(); file = ERR_PTR(err); if (!err) { - inode = nd.dentry->d_inode; file = ERR_PTR(-EACCES); - if (!IS_NOEXEC(inode) && S_ISREG(inode->i_mode)) { - int err = permission(inode, MAY_EXEC); + if (S_ISREG(nd.dentry->d_inode->i_mode)) { + int err = permission(nd.dentry->d_inode, MAY_EXEC); file = ERR_PTR(err); if (!err) { lock_kernel(); file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); unlock_kernel(); - if (!IS_ERR(file)) { - err = deny_write_access(file); - if (err) { - fput(file); - file = ERR_PTR(err); - } - } out: return file; } @@ -556,7 +530,7 @@ flush_failed: */ static inline int must_not_trace_exec(struct task_struct * p) { - return (p->ptrace&PT_PTRACED) && !cap_raised(p->p_pptr->cap_effective, CAP_SYS_PTRACE); + return (p->ptrace & PT_PTRACED) && !cap_raised(p->p_pptr->cap_effective, CAP_SYS_PTRACE); } /* @@ -566,13 +540,23 @@ static inline int must_not_trace_exec(struct task_struct * p) int prepare_binprm(struct linux_binprm *bprm) { int mode; - int id_change,cap_raised; + int retval,id_change,cap_raised; struct inode * inode = bprm->file->f_dentry->d_inode; mode = inode->i_mode; - /* Huh? We had already checked for MAY_EXEC, WTF do we check this? */ - if (!(mode & 0111)) /* with at least _one_ execute bit set */ + if (!S_ISREG(mode)) /* must be regular file */ + return -EACCES; + if (!(mode & 0111)) /* with at least _one_ execute bit set */ return -EACCES; + if (IS_NOEXEC(inode)) /* FS mustn't be mounted noexec */ + return -EACCES; + if (!inode->i_sb) + return -EACCES; + if ((retval = permission(inode, MAY_EXEC)) != 0) + return retval; + /* better not execute files which are being written to */ + if (atomic_read(&inode->i_writecount) > 0) + return -ETXTBSY; bprm->e_uid = current->euid; bprm->e_gid = current->egid; @@ -744,7 +728,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) char * dynloader[] = { "/sbin/loader" }; struct file * file; - allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; @@ -778,7 +761,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) retval = fn(bprm, regs); if (retval >= 0) { put_binfmt(fmt); - allow_write_access(bprm->file); if (bprm->file) fput(bprm->file); bprm->file = NULL; @@ -840,13 +822,11 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs bprm.loader = 0; bprm.exec = 0; if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) { - allow_write_access(file); fput(file); return bprm.argc; } if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) { - allow_write_access(file); fput(file); return bprm.envc; } @@ -875,7 +855,6 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs out: /* Something went wrong, return the inode and free the argument pages*/ - allow_write_access(bprm.file); if (bprm.file) fput(bprm.file); diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 97fb703e1..a3f8ae4ce 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -473,8 +473,11 @@ repeat: if (i >= sb->u.ext2_sb.s_groups_count) i = 0; gdp = ext2_get_group_desc (sb, i, &bh2); - if (!gdp) - goto io_error; + if (!gdp) { + *err = -EIO; + unlock_super (sb); + return 0; + } if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) break; } diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index cd62f058d..3a18b375c 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -26,7 +26,7 @@ struct file_operations ext2_dir_operations = { read: generic_read_dir, readdir: ext2_readdir, ioctl: ext2_ioctl, - fsync: ext2_fsync_file, + fsync: ext2_sync_file, }; int ext2_check_dir_entry (const char * function, struct inode * dir, diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 130013e50..d2c137e2c 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -91,7 +91,6 @@ static int ext2_open_file (struct inode * inode, struct file * filp) return 0; } - /* * We have mostly NULL's here: the current defaults are ok for * the ext2 filesystem. @@ -104,7 +103,7 @@ struct file_operations ext2_file_operations = { mmap: generic_file_mmap, open: ext2_open_file, release: ext2_release_file, - fsync: ext2_fsync_file, + fsync: ext2_sync_file, }; struct inode_operations ext2_file_inode_operations = { diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c index 5b58f6cad..52ffd6138 100644 --- a/fs/ext2/fsync.c +++ b/fs/ext2/fsync.c @@ -27,28 +27,131 @@ #include <linux/smp_lock.h> +#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb)) +#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb)) + +static int sync_indirect(struct inode * inode, u32 * block, int wait) +{ + struct buffer_head * bh; + + if (!*block) + return 0; + bh = get_hash_table(inode->i_dev, le32_to_cpu(*block), blocksize); + if (!bh) + return 0; + if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { + /* There can be a parallell read(2) that started read-I/O + on the buffer so we can't assume that there's been + an I/O error without first waiting I/O completation. */ + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) + { + brelse (bh); + return -1; + } + } + if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) { + if (wait) + /* when we return from fsync all the blocks + must be _just_ stored on disk */ + wait_on_buffer(bh); + brelse(bh); + return 0; + } + ll_rw_block(WRITE, 1, &bh); + atomic_dec(&bh->b_count); + return 0; +} + +static int sync_iblock(struct inode * inode, u32 * iblock, + struct buffer_head ** bh, int wait) +{ + int rc, tmp; + + *bh = NULL; + tmp = le32_to_cpu(*iblock); + if (!tmp) + return 0; + rc = sync_indirect(inode, iblock, wait); + if (rc) + return rc; + *bh = bread(inode->i_dev, tmp, blocksize); + if (!*bh) + return -1; + return 0; +} + +static int sync_dindirect(struct inode * inode, u32 * diblock, int wait) +{ + int i; + struct buffer_head * dind_bh; + int rc, err = 0; + + rc = sync_iblock(inode, diblock, &dind_bh, wait); + if (rc || !dind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_indirect(inode, ((u32 *) dind_bh->b_data) + i, wait); + if (rc) + err = rc; + } + brelse(dind_bh); + return err; +} + +static int sync_tindirect(struct inode * inode, u32 * tiblock, int wait) +{ + int i; + struct buffer_head * tind_bh; + int rc, err = 0; + + rc = sync_iblock(inode, tiblock, &tind_bh, wait); + if (rc || !tind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_dindirect(inode, ((u32 *) tind_bh->b_data) + i, wait); + if (rc) + err = rc; + } + brelse(tind_bh); + return err; +} + /* * File may be NULL when we are called. Perhaps we shouldn't * even pass file to fsync ? */ -int ext2_fsync_file(struct file * file, struct dentry *dentry, int datasync) +int ext2_sync_file(struct file * file, struct dentry *dentry) { + int wait, err = 0; struct inode *inode = dentry->d_inode; - return ext2_fsync_inode(inode, datasync); -} -int ext2_fsync_inode(struct inode *inode, int datasync) -{ - int err; - - err = fsync_inode_buffers(inode); - if (!(inode->i_state & I_DIRTY)) - return err; - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) - return err; - - err |= ext2_sync_inode(inode); + lock_kernel(); + if (S_ISLNK(inode->i_mode) && !(inode->i_blocks)) + /* + * Don't sync fast links! + */ + goto skip; + + err = generic_buffer_fdatasync(inode, 0, ~0UL); + + for (wait=0; wait<=1; wait++) + { + err |= sync_indirect(inode, + inode->u.ext2_i.i_data+EXT2_IND_BLOCK, + wait); + err |= sync_dindirect(inode, + inode->u.ext2_i.i_data+EXT2_DIND_BLOCK, + wait); + err |= sync_tindirect(inode, + inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, + wait); + } +skip: + err |= ext2_sync_inode (inode); + unlock_kernel(); return err ? -EIO : 0; } - diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index cbc806cda..3c95ccd70 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -287,6 +287,7 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err) repeat: gdp = NULL; i=0; + *err = -ENOSPC; if (S_ISDIR(mode)) { avefreei = le32_to_cpu(es->s_free_inodes_count) / sb->u.ext2_sb.s_groups_count; @@ -368,7 +369,6 @@ repeat: if (!gdp) { unlock_super (sb); iput(inode); - *err = -ENOSPC; return NULL; } bitmap_nr = load_inode_bitmap (sb, i); @@ -398,8 +398,9 @@ repeat: ext2_error (sb, "ext2_new_inode", "Free inodes count corrupted in group %d", i); - /* If we continue recover from this case */ - gdp->bg_free_inodes_count = 0; + unlock_super (sb); + iput (inode); + return NULL; } goto repeat; } @@ -410,7 +411,6 @@ repeat: "block_group = %d,inode=%d", i, j); unlock_super (sb); iput (inode); - *err = EIO; /* Should never happen */ return NULL; } gdp->bg_free_inodes_count = diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index d3abb7cb2..7e5263fb1 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -117,7 +117,7 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err) inode->u.ext2_i.i_prealloc_count--; ext2_debug ("preallocation hit (%lu/%lu).\n", ++alloc_hits, ++alloc_attempts); - *err = 0; + } else { ext2_discard_prealloc (inode); ext2_debug ("preallocation miss (%lu/%lu).\n", @@ -200,7 +200,6 @@ out: return ret; } -/* returns NULL and sets *err on error */ static struct buffer_head * inode_getblk (struct inode * inode, int nr, int new_block, int * err, int metadata, long *phys, int *new) { @@ -224,6 +223,7 @@ repeat: return NULL; } } + *err = -EFBIG; /* Check file limits.. */ { @@ -311,7 +311,7 @@ repeat: * can fail due to: - not present * - out of space * - * NULL return in the data case, or an error, is mandatory. + * NULL return in the data case is mandatory. */ static struct buffer_head * block_getblk (struct inode * inode, struct buffer_head * bh, int nr, @@ -341,7 +341,6 @@ repeat: if (tmp == le32_to_cpu(*p)) goto out; brelse (result); - result = NULL; goto repeat; } else { *phys = tmp; @@ -403,9 +402,11 @@ repeat: *new = 1; } *p = le32_to_cpu(tmp); - mark_buffer_dirty_inode(bh, 1, inode); - if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) + mark_buffer_dirty(bh, 1); + if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) { ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } inode->i_ctime = CURRENT_TIME; inode->i_blocks += blocksize/512; mark_inode_dirty(inode); @@ -486,9 +487,9 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head * #define GET_INODE_PTR(x) \ inode_getblk(inode, x, iblock, &err, 1, NULL, NULL) #define GET_INDIRECT_DATABLOCK(x) \ - block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new) + block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new); #define GET_INDIRECT_PTR(x) \ - block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL) + block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL); if (ptr < direct_blocks) { bh = GET_INODE_DATABLOCK(ptr); @@ -546,11 +547,13 @@ abort_too_big: struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err) { struct buffer_head dummy; + int error; dummy.b_state = 0; dummy.b_blocknr = -1000; - *err = ext2_get_block(inode, block, &dummy, create); - if (!*err && buffer_mapped(&dummy)) { + error = ext2_get_block(inode, block, &dummy, create); + *err = error; + if (!error && buffer_mapped(&dummy)) { struct buffer_head *bh; bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize); if (buffer_new(&dummy)) { @@ -878,23 +881,8 @@ static int ext2_update_inode(struct inode * inode, int do_sync) raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl); if (S_ISDIR(inode->i_mode)) raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl); - else { + else raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32); - if (inode->i_size >> 31) { - struct super_block *sb = inode->i_sb; - struct ext2_super_block *es = sb->u.ext2_sb.s_es; - if (!(es->s_feature_ro_compat & cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) { - /* If this is the first large file - * created, add a flag to the superblock - * SMP Note: we're currently protected by the - * big kernel lock here, so this will need - * to be changed if that's no longer true. - */ - es->s_feature_ro_compat |= cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE); - ext2_write_super(sb); - } - } - } raw_inode->i_generation = cpu_to_le32(inode->i_generation); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) @@ -916,10 +904,10 @@ static int ext2_update_inode(struct inode * inode, int do_sync) return err; } -void ext2_write_inode (struct inode * inode, int wait) +void ext2_write_inode (struct inode * inode) { lock_kernel(); - ext2_update_inode (inode, wait); + ext2_update_inode (inode, 0); unlock_kernel(); } diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 116b4852f..46e273935 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -366,9 +366,12 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode) struct inode * inode; int err; + /* + * N.B. Several error exits in ext2_new_inode don't set err. + */ inode = ext2_new_inode (dir, mode, &err); if (!inode) - return err; + return -EIO; inode->i_op = &ext2_file_inode_operations; inode->i_fop = &ext2_file_operations; @@ -394,7 +397,7 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int inode = ext2_new_inode (dir, mode, &err); if (!inode) - return err; + return -EIO; inode->i_uid = current->fsuid; init_special_inode(inode, mode, rdev); @@ -425,7 +428,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) inode = ext2_new_inode (dir, S_IFDIR, &err); if (!inode) - return err; + return -EIO; inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; @@ -451,7 +454,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) strcpy (de->name, ".."); ext2_set_de_type(dir->i_sb, de, S_IFDIR); inode->i_nlink = 2; - mark_buffer_dirty_inode(dir_block, 1, dir); + mark_buffer_dirty(dir_block, 1); brelse (dir_block); inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) @@ -631,7 +634,7 @@ static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * return -ENAMETOOLONG; if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) - return err; + return -EIO; inode->i_mode = S_IFLNK | S_IRWXUGO; @@ -788,7 +791,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, mark_inode_dirty(old_dir); if (dir_bh) { PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino); - mark_buffer_dirty_inode(dir_bh, 1, old_inode); + mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; mark_inode_dirty(old_dir); if (new_inode) { diff --git a/fs/ext2/super.c b/fs/ext2/super.c index d3af3b992..aa6a599fc 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -593,6 +593,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, /* * set up enough so that it can read an inode */ + sb->s_dev = dev; sb->s_op = &ext2_sops; sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO)); if (!sb->s_root) { diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c index 1c05cc09f..ba8397196 100644 --- a/fs/ext2/truncate.c +++ b/fs/ext2/truncate.c @@ -211,7 +211,7 @@ static int trunc_indirect (struct inode * inode, int offset, u32 * p, struct buf inode->i_ino, tmp); *p = 0; if (dind_bh) - mark_buffer_dirty_inode(dind_bh, 1, inode); + mark_buffer_dirty(dind_bh, 1); else mark_inode_dirty(inode); return 0; @@ -279,7 +279,7 @@ static int trunc_dindirect (struct inode * inode, int offset, u32 * p, inode->i_ino, tmp); *p = 0; if (tind_bh) - mark_buffer_dirty_inode(tind_bh, 1, inode); + mark_buffer_dirty(tind_bh, 1); else mark_inode_dirty(inode); return 0; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 8b29c563e..85cc4e1a6 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -837,7 +837,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) MSDOS_I(inode)->i_ctime_ms = de->ctime_ms; } -void fat_write_inode(struct inode *inode, int unused) +void fat_write_inode(struct inode *inode) { struct super_block *sb = inode->i_sb; struct buffer_head *bh; diff --git a/fs/fcntl.c b/fs/fcntl.c index 37e32a012..f6e4e1651 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -252,8 +252,8 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) err = sock_fcntl (filp, cmd, arg); break; } - unlock_kernel(); fput(filp); + unlock_kernel(); out: return err; } diff --git a/fs/file_table.c b/fs/file_table.c index ceb3b7069..ecaa46896 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -16,7 +16,9 @@ static kmem_cache_t *filp_cache; /* sysctl tunables... */ -struct files_stat_struct files_stat = {0, 0, NR_FILE}; +int nr_files; /* read only */ +int nr_free_files; /* read only */ +int max_files = NR_FILE;/* tunable */ /* Here the new files go */ static LIST_HEAD(anon_list); @@ -51,11 +53,11 @@ struct file * get_empty_filp(void) struct file * f; file_list_lock(); - if (files_stat.nr_free_files > NR_RESERVED_FILES) { + if (nr_free_files > NR_RESERVED_FILES) { used_one: f = list_entry(free_list.next, struct file, f_list); list_del(&f->f_list); - files_stat.nr_free_files--; + nr_free_files--; new_one: file_list_unlock(); memset(f, 0, sizeof(*f)); @@ -71,25 +73,25 @@ struct file * get_empty_filp(void) /* * Use a reserved one if we're the superuser */ - if (files_stat.nr_free_files && !current->euid) + if (nr_free_files && !current->euid) goto used_one; /* * Allocate a new one if we're below the limit. */ - if (files_stat.nr_files < files_stat.max_files) { + if (nr_files < max_files) { file_list_unlock(); f = kmem_cache_alloc(filp_cache, SLAB_KERNEL); file_list_lock(); if (f) { - files_stat.nr_files++; + nr_files++; goto new_one; } /* Big problems... */ printk("VFS: filp allocation failed\n"); - } else if (files_stat.max_files > old_max) { - printk("VFS: file-max limit %d reached\n", files_stat.max_files); - old_max = files_stat.max_files; + } else if (max_files > old_max) { + printk("VFS: file-max limit %d reached\n", max_files); + old_max = max_files; } file_list_unlock(); return NULL; @@ -98,8 +100,7 @@ struct file * get_empty_filp(void) /* * Clear and initialize a (private) struct file for the given dentry, * and call the open function (if any). The caller must verify that - * inode->i_fop is not NULL. The only user is nfsfh.c and this function - * will eventually go away. + * inode->i_fop is not NULL. */ int init_private_file(struct file *filp, struct dentry *dentry, int mode) { @@ -147,7 +148,7 @@ void _fput(struct file *file) file_list_lock(); list_del(&file->f_list); list_add(&file->f_list, &free_list); - files_stat.nr_free_files++; + nr_free_files++; file_list_unlock(); } @@ -159,7 +160,7 @@ void put_filp(struct file *file) file_list_lock(); list_del(&file->f_list); list_add(&file->f_list, &free_list); - files_stat.nr_free_files++; + nr_free_files++; file_list_unlock(); } } diff --git a/fs/filesystems.c b/fs/filesystems.c index 22f6aa6db..ce64f4c8e 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -52,7 +52,7 @@ void __init filesystem_setup(void) #ifdef CONFIG_NFSD_MODULE int (*do_nfsservctl)(int, void *, void *); #endif -int +long asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp) { #ifndef CONFIG_NFSD_MODULE diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index ebe12eb40..c0707b52c 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -56,7 +56,7 @@ void hpfs_truncate(struct inode *i) i->i_blocks = 1 + ((i->i_size + 511) >> 9); i->u.hpfs_i.mmu_private = i->i_size; hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); - hpfs_write_inode(i, 0); + hpfs_write_inode(i); } int hpfs_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create) diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index a76efa035..a01140f1f 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -266,7 +266,7 @@ ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t void hpfs_read_inode(struct inode *); void hpfs_write_inode_ea(struct inode *, struct fnode *); -void hpfs_write_inode(struct inode *, int); +void hpfs_write_inode(struct inode *); void hpfs_write_inode_nolock(struct inode *); int hpfs_notify_change(struct dentry *, struct iattr *); void hpfs_write_if_changed(struct inode *); diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 2f3f3f32e..7938970c8 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -228,7 +228,7 @@ void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode) } } -void hpfs_write_inode(struct inode *i, int unused) +void hpfs_write_inode(struct inode *i) { struct inode *parent; if (!i->i_nlink) return; @@ -300,14 +300,14 @@ int hpfs_notify_change(struct dentry *dentry, struct iattr *attr) if (inode->i_sb->s_hpfs_root == inode->i_ino) return -EINVAL; if ((error = inode_change_ok(inode, attr))) return error; inode_setattr(inode, attr); - hpfs_write_inode(inode, 0); + hpfs_write_inode(inode); return 0; } void hpfs_write_if_changed(struct inode *inode) { if (inode->i_hpfs_dirty) { - hpfs_write_inode(inode, 0); + hpfs_write_inode(inode); } } diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 5684801df..b09ad98ea 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -330,15 +330,7 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry) struct iattr newattrs; int err; hpfs_unlock_2inodes(dir, inode); - if (rep) - goto ret; - d_drop(dentry); - if (dentry->d_count > 1 || - permission(inode, MAY_WRITE) || - get_write_access(inode)) { - d_rehash(dentry); - goto ret; - } + if (rep || dentry->d_count > 1 || permission(inode, MAY_WRITE) || get_write_access(inode)) goto ret; /*printk("HPFS: truncating file before delete.\n");*/ down(&inode->i_sem); newattrs.ia_size = 0; diff --git a/fs/inode.c b/fs/inode.c index 27159b951..e46359b03 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -96,7 +96,6 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) INIT_LIST_HEAD(&inode->i_hash); INIT_LIST_HEAD(&inode->i_data.pages); INIT_LIST_HEAD(&inode->i_dentry); - INIT_LIST_HEAD(&inode->i_dirty_buffers); sema_init(&inode->i_sem, 1); sema_init(&inode->i_zombie, 1); spin_lock_init(&inode->i_data.i_shared_lock); @@ -123,14 +122,14 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) * Mark an inode as dirty. Callers should use mark_inode_dirty. */ -void __mark_inode_dirty(struct inode *inode, int flags) +void __mark_inode_dirty(struct inode *inode) { struct super_block * sb = inode->i_sb; if (sb) { spin_lock(&inode_lock); - if ((inode->i_state & flags) != flags) { - inode->i_state |= flags; + if (!(inode->i_state & I_DIRTY)) { + inode->i_state |= I_DIRTY; /* Only add valid (ie hashed) inodes to the dirty list */ if (!list_empty(&inode->i_hash)) { list_del(&inode->i_list); @@ -163,10 +162,10 @@ static inline void wait_on_inode(struct inode *inode) } -static inline void write_inode(struct inode *inode, int wait) +static inline void write_inode(struct inode *inode) { if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode) - inode->i_sb->s_op->write_inode(inode, wait); + inode->i_sb->s_op->write_inode(inode); } static inline void __iget(struct inode * inode) @@ -183,7 +182,7 @@ static inline void __iget(struct inode * inode) inodes_stat.nr_unused--; } -static inline void sync_one(struct inode *inode, int wait) +static inline void sync_one(struct inode *inode) { if (inode->i_state & I_LOCK) { __iget(inode); @@ -197,11 +196,10 @@ static inline void sync_one(struct inode *inode, int wait) ? &inode_in_use : &inode_unused); /* Set I_LOCK, reset I_DIRTY */ - inode->i_state |= I_LOCK; - inode->i_state &= ~I_DIRTY; + inode->i_state ^= I_DIRTY | I_LOCK; spin_unlock(&inode_lock); - write_inode(inode, wait); + write_inode(inode); spin_lock(&inode_lock); inode->i_state &= ~I_LOCK; @@ -214,7 +212,7 @@ static inline void sync_list(struct list_head *head) struct list_head * tmp; while ((tmp = head->prev) != head) - sync_one(list_entry(tmp, struct inode, i_list), 0); + sync_one(list_entry(tmp, struct inode, i_list)); } /** @@ -247,7 +245,6 @@ void sync_inodes(kdev_t dev) spin_unlock(&inode_lock); } - /* * Called with the spinlock already held.. */ @@ -264,20 +261,19 @@ static void sync_all_inodes(void) /** * write_inode_now - write an inode to disk * @inode: inode to write to disk - * @wait: if set, we wait for the write to complete on disk * * This function commits an inode to disk immediately if it is * dirty. This is primarily needed by knfsd. */ -void write_inode_now(struct inode *inode, int wait) +void write_inode_now(struct inode *inode) { struct super_block * sb = inode->i_sb; if (sb) { spin_lock(&inode_lock); while (inode->i_state & I_DIRTY) - sync_one(inode, wait); + sync_one(inode); spin_unlock(&inode_lock); } else @@ -285,60 +281,6 @@ void write_inode_now(struct inode *inode, int wait) } /** - * generic_osync_inode - flush all dirty data for a given inode to disk - * @inode: inode to write - * @datasync: if set, don't bother flushing timestamps - * - * This is called by generic_file_write for files which have the O_SYNC - * flag set, to flush dirty writes to disk. - */ - -int generic_osync_inode(struct inode *inode, int datasync) -{ - int err; - - /* - * WARNING - * - * Currently, the filesystem write path does not pass the - * filp down to the low-level write functions. Therefore it - * is impossible for (say) __block_commit_write to know if - * the operation is O_SYNC or not. - * - * Ideally, O_SYNC writes would have the filesystem call - * ll_rw_block as it went to kick-start the writes, and we - * could call osync_inode_buffers() here to wait only for - * those IOs which have already been submitted to the device - * driver layer. As it stands, if we did this we'd not write - * anything to disk since our writes have not been queued by - * this point: they are still on the dirty LRU. - * - * So, currently we will call fsync_inode_buffers() instead, - * to flush _all_ dirty buffers for this inode to disk on - * every O_SYNC write, not just the synchronous I/Os. --sct - */ - -#ifdef WRITERS_QUEUE_IO - err = osync_inode_buffers(inode); -#else - err = fsync_inode_buffers(inode); -#endif - - spin_lock(&inode_lock); - if (!(inode->i_state & I_DIRTY)) - goto out; - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) - goto out; - spin_unlock(&inode_lock); - write_inode_now(inode, 1); - return err; - - out: - spin_unlock(&inode_lock); - return err; -} - -/** * clear_inode - clear an inode * @inode: inode to clear * @@ -382,7 +324,7 @@ static void dispose_list(struct list_head * head) inode = list_entry(inode_entry, struct inode, i_list); if (inode->i_data.nrpages) - truncate_all_inode_pages(&inode->i_data); + truncate_inode_pages(&inode->i_data, 0); clear_inode(inode); destroy_inode(inode); } @@ -407,7 +349,6 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru inode = list_entry(tmp, struct inode, i_list); if (inode->i_sb != sb) continue; - invalidate_inode_buffers(inode); if (!atomic_read(&inode->i_count)) { list_del(&inode->i_hash); INIT_LIST_HEAD(&inode->i_hash); @@ -469,8 +410,7 @@ int invalidate_inodes(struct super_block * sb) * dispose_list. */ #define CAN_UNUSE(inode) \ - ((((inode)->i_state | (inode)->i_data.nrpages) == 0) && \ - !inode_has_buffers(inode)) + (((inode)->i_state | (inode)->i_data.nrpages) == 0) #define INODE(entry) (list_entry(entry, struct inode, i_list)) void prune_icache(int goal) @@ -830,7 +770,7 @@ void iput(struct inode *inode) spin_unlock(&inode_lock); if (inode->i_data.nrpages) - truncate_all_inode_pages(&inode->i_data); + truncate_inode_pages(&inode->i_data, 0); destroy = 1; if (op && op->delete_inode) { @@ -985,7 +925,7 @@ void update_atime (struct inode *inode) if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return; if ( IS_RDONLY (inode) ) return; inode->i_atime = CURRENT_TIME; - mark_inode_dirty_sync (inode); + mark_inode_dirty (inode); } /* End Function update_atime */ diff --git a/fs/ioctl.c b/fs/ioctl.c index f02d766bd..16ad5ec26 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -107,8 +107,8 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) else if (filp->f_op && filp->f_op->ioctl) error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); } - unlock_kernel(); fput(filp); + unlock_kernel(); out: return error; diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index a3a4f072f..f89188d12 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -162,7 +162,8 @@ reclaimer(void *ptr) { struct nlm_host *host = (struct nlm_host *) ptr; struct nlm_wait *block; - struct list_head *tmp; + struct file_lock *fl; + struct inode *inode; /* This one ensures that our parent doesn't terminate while the * reclaim is in progress */ @@ -170,21 +171,19 @@ reclaimer(void *ptr) lockd_up(); /* First, reclaim all locks that have been granted previously. */ -restart: - tmp = file_lock_list.next; - while (tmp != &file_lock_list) { - struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); - struct inode *inode = fl->fl_file->f_dentry->d_inode; - if (inode->i_sb->s_magic == NFS_SUPER_MAGIC && - nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr) && - fl->fl_u.nfs_fl.state != host->h_state && - (fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) { - fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED; - nlmclnt_reclaim(host, fl); - goto restart; + do { + for (fl = file_lock_table; fl; fl = fl->fl_nextlink) { + inode = fl->fl_file->f_dentry->d_inode; + if (inode->i_sb->s_magic == NFS_SUPER_MAGIC + && nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr) + && fl->fl_u.nfs_fl.state != host->h_state + && (fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) { + fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED; + nlmclnt_reclaim(host, fl); + break; + } } - tmp = tmp->next; - } + } while (fl); host->h_reclaiming = 0; wake_up(&host->h_gracewait); diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 56c8d8173..279fcc3c1 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -347,7 +347,7 @@ again: /* Append to list of blocked */ nlmsvc_insert_block(block, NLM_NEVER); - if (!list_empty(&block->b_call.a_args.lock.fl.fl_block)) { + if (!block->b_call.a_args.lock.fl.fl_prevblock) { /* Now add block to block list of the conflicting lock if we haven't done so. */ dprintk("lockd: blocking on this lock.\n"); diff --git a/fs/locks.c b/fs/locks.c index c8710dcc4..015b8e87a 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -108,150 +108,57 @@ #include <linux/malloc.h> #include <linux/file.h> #include <linux/smp_lock.h> -#include <linux/init.h> #include <asm/uaccess.h> -LIST_HEAD(file_lock_list); -static LIST_HEAD(blocked_list); - -static kmem_cache_t *filelock_cache; - -/* Allocate an empty lock structure. */ -static struct file_lock *locks_alloc_lock(void) +static int flock_make_lock(struct file *filp, struct file_lock *fl, + unsigned int cmd); +static int posix_make_lock(struct file *filp, struct file_lock *fl, + struct flock *l); +static int flock_locks_conflict(struct file_lock *caller_fl, + struct file_lock *sys_fl); +static int posix_locks_conflict(struct file_lock *caller_fl, + struct file_lock *sys_fl); +static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl); +static int flock_lock_file(struct file *filp, struct file_lock *caller, + unsigned int wait); +static int posix_locks_deadlock(struct file_lock *caller, + struct file_lock *blocker); + +static struct file_lock *locks_empty_lock(void); +static struct file_lock *locks_init_lock(struct file_lock *, + struct file_lock *); +static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl); +static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait); +static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx); + +static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter); +static void locks_delete_block(struct file_lock *blocker, struct file_lock *waiter); +static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait); + +struct file_lock *file_lock_table = NULL; + +/* Allocate a new lock, and initialize its fields from fl. + * The lock is not inserted into any lists until locks_insert_lock() or + * locks_insert_block() are called. + */ +static inline struct file_lock *locks_alloc_lock(struct file_lock *fl) { - struct file_lock *fl; - fl = kmem_cache_alloc(filelock_cache, SLAB_KERNEL); - return fl; + return locks_init_lock(locks_empty_lock(), fl); } -/* Free a lock which is not in use. */ +/* Free lock not inserted in any queue. + */ static inline 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)) + if (fl->fl_nextblock != NULL || fl->fl_prevblock != NULL) panic("Attempting to free lock with active block list"); - - if (!list_empty(&fl->fl_link)) - panic("Attempting to free lock on active lock list"); - - kmem_cache_free(filelock_cache, fl); -} - -/* - * Initialises the fields of the file lock which are invariant for - * free file_locks. - */ -static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags) -{ - struct file_lock *lock = (struct file_lock *) foo; - - if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) != - SLAB_CTOR_CONSTRUCTOR) - return; - - lock->fl_next = NULL; - INIT_LIST_HEAD(&lock->fl_link); - INIT_LIST_HEAD(&lock->fl_block); - init_waitqueue_head(&lock->fl_wait); -} - -/* - * Initialize a new lock from an existing file_lock structure. - */ -static void locks_copy_lock(struct file_lock *new, struct file_lock *fl) -{ - new->fl_owner = fl->fl_owner; - new->fl_pid = fl->fl_pid; - new->fl_file = fl->fl_file; - new->fl_flags = fl->fl_flags; - new->fl_type = fl->fl_type; - new->fl_start = fl->fl_start; - new->fl_end = fl->fl_end; - new->fl_notify = fl->fl_notify; - new->fl_insert = fl->fl_insert; - new->fl_remove = fl->fl_remove; - new->fl_u = fl->fl_u; -} - -/* Fill in a file_lock structure with an appropriate FLOCK lock. */ -static struct file_lock *flock_make_lock(struct file *filp, unsigned int type) -{ - struct file_lock *fl = locks_alloc_lock(); - if (fl == NULL) - return NULL; - - fl->fl_owner = NULL; - fl->fl_file = filp; - fl->fl_pid = current->pid; - fl->fl_flags = FL_FLOCK; - fl->fl_type = type; - fl->fl_start = 0; - fl->fl_end = OFFSET_MAX; - fl->fl_notify = NULL; - fl->fl_insert = NULL; - fl->fl_remove = NULL; - - return fl; -} - -/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX - * style lock. - */ -static int posix_make_lock(struct file *filp, struct file_lock *fl, - struct flock *l) -{ - loff_t start; - - switch (l->l_whence) { - case 0: /*SEEK_SET*/ - start = 0; - break; - case 1: /*SEEK_CUR*/ - start = filp->f_pos; - break; - case 2: /*SEEK_END*/ - start = filp->f_dentry->d_inode->i_size; - break; - default: - return (0); - } - - if (((start += l->l_start) < 0) || (l->l_len < 0)) - return (0); - fl->fl_end = start + l->l_len - 1; - if (l->l_len > 0 && fl->fl_end < 0) - return (0); - fl->fl_start = start; /* we record the absolute position */ - if (l->l_len == 0) - fl->fl_end = OFFSET_MAX; - - fl->fl_owner = current->files; - fl->fl_pid = current->pid; - fl->fl_file = filp; - fl->fl_flags = FL_POSIX; - fl->fl_notify = NULL; - fl->fl_insert = NULL; - fl->fl_remove = NULL; - - switch (l->l_type) { - case F_RDLCK: - case F_WRLCK: - case F_UNLCK: - fl->fl_type = l->l_type; - break; - default: - return (0); - } - - return (1); + + kfree(fl); + return; } /* Check if two locks overlap each other. @@ -274,17 +181,6 @@ locks_same_owner(struct file_lock *fl1, struct file_lock *fl2) (fl1->fl_pid == fl2->fl_pid); } -/* Remove waiter from blocker's block list. - * When blocker ends up pointing to itself then the list is empty. - */ -static void locks_delete_block(struct file_lock *waiter) -{ - list_del(&waiter->fl_block); - INIT_LIST_HEAD(&waiter->fl_block); - list_del(&waiter->fl_link); - INIT_LIST_HEAD(&waiter->fl_link); -} - /* Insert waiter into blocker's block list. * We use a circular list so that processes can be easily woken up in * the order they blocked. The documentation doesn't require this but @@ -293,15 +189,71 @@ static void locks_delete_block(struct file_lock *waiter) static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter) { - if (!list_empty(&waiter->fl_block)) { - printk(KERN_ERR "locks_insert_block: removing duplicated lock " - "(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid, - waiter->fl_start, waiter->fl_end, waiter->fl_type); - locks_delete_block(waiter); + struct file_lock *prevblock; + + if (waiter->fl_prevblock) { + printk(KERN_ERR "locks_insert_block: remove duplicated lock " + "(pid=%d %Ld-%Ld type=%d)\n", + waiter->fl_pid, (long long)waiter->fl_start, + (long long)waiter->fl_end, waiter->fl_type); + locks_delete_block(waiter->fl_prevblock, waiter); } - list_add_tail(&waiter->fl_block, &blocker->fl_block); -// list_add(&waiter->fl_link, &blocked_list); -// waiter->fl_next = blocker; + + if (blocker->fl_prevblock == NULL) + /* No previous waiters - list is empty */ + prevblock = blocker; + else + /* Previous waiters exist - add to end of list */ + prevblock = blocker->fl_prevblock; + + prevblock->fl_nextblock = waiter; + blocker->fl_prevblock = waiter; + waiter->fl_nextblock = blocker; + waiter->fl_prevblock = prevblock; + + return; +} + +/* Remove waiter from blocker's block list. + * When blocker ends up pointing to itself then the list is empty. + */ +static void locks_delete_block(struct file_lock *blocker, + struct file_lock *waiter) +{ + struct file_lock *nextblock; + struct file_lock *prevblock; + + nextblock = waiter->fl_nextblock; + prevblock = waiter->fl_prevblock; + + if (nextblock == NULL) + return; + + nextblock->fl_prevblock = prevblock; + prevblock->fl_nextblock = nextblock; + + waiter->fl_prevblock = waiter->fl_nextblock = NULL; + if (blocker->fl_nextblock == blocker) + /* No more locks on blocker's blocked list */ + blocker->fl_prevblock = blocker->fl_nextblock = NULL; + return; +} + +/* The following two are for the benefit of lockd. + */ +void +posix_block_lock(struct file_lock *blocker, struct file_lock *waiter) +{ + locks_insert_block(blocker, waiter); + return; +} + +void +posix_unblock_lock(struct file_lock *waiter) +{ + if (waiter->fl_prevblock) + locks_delete_block(waiter->fl_prevblock, waiter); + return; } /* Wake up processes blocked waiting for blocker. @@ -310,8 +262,9 @@ static void locks_insert_block(struct file_lock *blocker, */ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait) { - while (!list_empty(&blocker->fl_block)) { - struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_block); + struct file_lock *waiter; + + while ((waiter = blocker->fl_nextblock) != NULL) { /* N.B. Is it possible for the notify function to block?? */ if (waiter->fl_notify) waiter->fl_notify(waiter); @@ -326,105 +279,262 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait) /* Remove waiter from the block list, because by the * time it wakes up blocker won't exist any more. */ - locks_delete_block(waiter); + locks_delete_block(blocker, waiter); } } + return; } -/* Insert file lock fl into an inode's lock list at the position indicated - * by pos. At the same time add the lock to the global file lock list. +/* flock() system call entry point. Apply a FL_FLOCK style lock to + * an open file descriptor. */ -static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) +asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) { - list_add(&fl->fl_link, &file_lock_list); - - /* insert into file's list */ - fl->fl_next = *pos; - *pos = fl; + struct file_lock file_lock; + struct file *filp; + int error; - if (fl->fl_insert) - fl->fl_insert(fl); + lock_kernel(); + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + error = -EINVAL; + if (!flock_make_lock(filp, &file_lock, cmd)) + goto out_putf; + error = -EBADF; + if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) + goto out_putf; + error = flock_lock_file(filp, &file_lock, + (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); +out_putf: + fput(filp); +out: + unlock_kernel(); + return (error); } -/* Delete a lock and free it. - * First remove our lock from the active lock lists. Then call - * locks_wake_up_blocks() to wake up processes that are blocked - * waiting for this lock. Finally free the lock structure. +/* Report the first existing lock that would conflict with l. + * This implements the F_GETLK command of fcntl(). */ -static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait) +int fcntl_getlk(unsigned int fd, struct flock *l) { - int (*lock)(struct file *, int, struct file_lock *); - struct file_lock *fl = *thisfl_p; + struct file *filp; + struct file_lock *fl,file_lock; + struct flock flock; + int error; - *thisfl_p = fl->fl_next; - fl->fl_next = NULL; + error = -EFAULT; + if (copy_from_user(&flock, l, sizeof(flock))) + goto out; + error = -EINVAL; + if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) + goto out; - list_del(&fl->fl_link); - INIT_LIST_HEAD(&fl->fl_link); + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; - if (fl->fl_remove) - fl->fl_remove(fl); + if (!posix_make_lock(filp, &file_lock, &flock)) + goto out_putf; - locks_wake_up_blocks(fl, wait); - lock = fl->fl_file->f_op->lock; - if (lock) { - fl->fl_type = F_UNLCK; - lock(fl->fl_file, F_SETLK, fl); + if (filp->f_op->lock) { + error = filp->f_op->lock(filp, F_GETLK, &file_lock); + if (error < 0) + goto out_putf; + else if (error == LOCK_USE_CLNT) + /* Bypass for NFS with no locking - 2.0.36 compat */ + fl = posix_test_lock(filp, &file_lock); + else + fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); + } else { + fl = posix_test_lock(filp, &file_lock); + } + + flock.l_type = F_UNLCK; + if (fl != NULL) { + flock.l_pid = fl->fl_pid; + flock.l_start = fl->fl_start; + flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : + fl->fl_end - fl->fl_start + 1; + flock.l_whence = 0; + flock.l_type = fl->fl_type; } - locks_free_lock(fl); + error = -EFAULT; + if (!copy_to_user(l, &flock, sizeof(flock))) + error = 0; + +out_putf: + fput(filp); +out: + return error; } -/* Determine if lock sys_fl blocks lock caller_fl. Common functionality - * checks for overlapping locks and shared/exclusive status. +/* Apply the lock described by l to an open file descriptor. + * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */ -static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) +int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) { - if (!locks_overlap(caller_fl, sys_fl)) - return (0); + struct file *filp; + struct file_lock file_lock; + struct flock flock; + struct inode *inode; + int error; - switch (caller_fl->fl_type) { + /* + * This might block, so we do it before checking the inode. + */ + error = -EFAULT; + if (copy_from_user(&flock, l, sizeof(flock))) + goto out; + + /* Get arguments and validate them ... + */ + + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + error = -EINVAL; + inode = filp->f_dentry->d_inode; + + /* Don't allow mandatory locks on files that may be memory mapped + * and shared. + */ + if (IS_MANDLOCK(inode) && + (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { + struct vm_area_struct *vma; + struct address_space *mapping = inode->i_mapping; + spin_lock(&mapping->i_shared_lock); + for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) { + if (!(vma->vm_flags & VM_MAYSHARE)) + continue; + spin_unlock(&mapping->i_shared_lock); + error = -EAGAIN; + goto out_putf; + } + spin_unlock(&mapping->i_shared_lock); + } + + error = -EINVAL; + if (!posix_make_lock(filp, &file_lock, &flock)) + goto out_putf; + + error = -EBADF; + switch (flock.l_type) { case F_RDLCK: - return (sys_fl->fl_type == F_WRLCK); - + if (!(filp->f_mode & FMODE_READ)) + goto out_putf; + break; case F_WRLCK: - return (1); - - default: - printk("locks_conflict(): impossible lock type - %d\n", - caller_fl->fl_type); + if (!(filp->f_mode & FMODE_WRITE)) + goto out_putf; + break; + case F_UNLCK: break; + case F_SHLCK: + case F_EXLCK: +#ifdef __sparc__ +/* warn a bit for now, but don't overdo it */ +{ + static int count = 0; + if (!count) { + count=1; + printk(KERN_WARNING + "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n", + current->pid, current->comm); } - return (0); /* This should never happen */ } + if (!(filp->f_mode & 3)) + goto out_putf; + break; +#endif + default: + error = -EINVAL; + goto out_putf; + } -/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific - * checking before calling the locks_conflict(). + if (filp->f_op->lock != NULL) { + error = filp->f_op->lock(filp, cmd, &file_lock); + if (error < 0) + goto out_putf; + } + error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW); + +out_putf: + fput(filp); +out: + return error; +} + +/* + * This function is called when the file is being removed + * from the task's fd array. */ -static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) +void locks_remove_posix(struct file *filp, fl_owner_t owner) { - /* POSIX locks owned by the same process do not conflict with - * each other. - */ - if (!(sys_fl->fl_flags & FL_POSIX) || - locks_same_owner(caller_fl, sys_fl)) - return (0); + struct inode * inode = filp->f_dentry->d_inode; + struct file_lock file_lock, *fl; + struct file_lock **before; - return (locks_conflict(caller_fl, sys_fl)); + /* + * For POSIX locks we free all locks on this file for the given task. + */ +repeat: + before = &inode->i_flock; + while ((fl = *before) != NULL) { + if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) { + int (*lock)(struct file *, int, struct file_lock *); + lock = filp->f_op->lock; + if (lock) { + file_lock = *fl; + file_lock.fl_type = F_UNLCK; + } + locks_delete_lock(before, 0); + if (lock) { + lock(filp, F_SETLK, &file_lock); + /* List may have changed: */ + goto repeat; + } + continue; + } + before = &fl->fl_next; + } } -/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific - * checking before calling the locks_conflict(). +/* + * This function is called on the last close of an open file. */ -static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) +void locks_remove_flock(struct file *filp) { - /* FLOCK locks referring to the same filp do not conflict with - * each other. - */ - if (!(sys_fl->fl_flags & FL_FLOCK) || - (caller_fl->fl_file == sys_fl->fl_file)) - return (0); + struct inode * inode = filp->f_dentry->d_inode; + struct file_lock file_lock, *fl; + struct file_lock **before; - return (locks_conflict(caller_fl, sys_fl)); +repeat: + before = &inode->i_flock; + while ((fl = *before) != NULL) { + if ((fl->fl_flags & FL_FLOCK) && fl->fl_file == filp) { + int (*lock)(struct file *, int, struct file_lock *); + lock = NULL; + if (filp->f_op) + lock = filp->f_op->lock; + if (lock) { + file_lock = *fl; + file_lock.fl_type = F_UNLCK; + } + locks_delete_lock(before, 0); + if (lock) { + lock(filp, F_SETLK, &file_lock); + /* List may have changed: */ + goto repeat; + } + continue; + } + before = &fl->fl_next; + } } struct file_lock * @@ -442,57 +552,6 @@ posix_test_lock(struct file *filp, struct file_lock *fl) return (cfl); } -/* This function tests for deadlock condition before putting a process to - * sleep. The detection scheme is no longer recursive. Recursive was neat, - * but dangerous - we risked stack corruption if the lock data was bad, or - * if the recursion was too deep for any other reason. - * - * We rely on the fact that a task can only be on one lock's wait queue - * at a time. When we find blocked_task on a wait queue we can re-search - * with blocked_task equal to that queue's owner, until either blocked_task - * isn't found, or blocked_task is found on a queue owned by my_task. - * - * Note: the above assumption may not be true when handling lock requests - * from a broken NFS client. But broken NFS clients have a lot more to - * worry about than proper deadlock detection anyway... --okir - */ -static int posix_locks_deadlock(struct file_lock *caller_fl, - struct file_lock *block_fl) -{ - struct list_head *tmp; - void *caller_owner, *blocked_owner; - unsigned int caller_pid, blocked_pid; - - caller_owner = caller_fl->fl_owner; - caller_pid = caller_fl->fl_pid; - blocked_owner = block_fl->fl_owner; - blocked_pid = block_fl->fl_pid; - -next_task: - if (caller_owner == blocked_owner && caller_pid == blocked_pid) - return 1; - list_for_each(tmp, &file_lock_list) { - struct list_head *btmp; - struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); - if (fl->fl_owner == NULL || list_empty(&fl->fl_block)) - continue; - list_for_each(btmp, &fl->fl_block) { - struct file_lock *bfl = list_entry(tmp, struct file_lock, fl_block); - if (bfl->fl_owner == blocked_owner && - bfl->fl_pid == blocked_pid) { - if (fl->fl_owner == caller_owner && - fl->fl_pid == caller_pid) { - return (1); - } - blocked_owner = fl->fl_owner; - blocked_pid = fl->fl_pid; - goto next_task; - } - } - } - return 0; -} - int locks_mandatory_locked(struct inode *inode) { fl_owner_t owner = current->files; @@ -517,16 +576,19 @@ int locks_mandatory_area(int read_write, struct inode *inode, size_t count) { struct file_lock *fl; - struct file_lock *new_fl = locks_alloc_lock(); + struct file_lock tfl; int error; - new_fl->fl_owner = current->files; - new_fl->fl_pid = current->pid; - new_fl->fl_file = filp; - new_fl->fl_flags = FL_POSIX | FL_ACCESS; - new_fl->fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK; - new_fl->fl_start = offset; - new_fl->fl_end = offset + count - 1; + memset(&tfl, 0, sizeof(tfl)); + + tfl.fl_file = filp; + tfl.fl_flags = FL_POSIX | FL_ACCESS; + tfl.fl_owner = current->files; + tfl.fl_pid = current->pid; + init_waitqueue_head(&tfl.fl_wait); + tfl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK; + tfl.fl_start = offset; + tfl.fl_end = offset + count - 1; error = 0; lock_kernel(); @@ -544,7 +606,7 @@ repeat: /* Block for writes against a "read" lock, * and both reads and writes against a "write" lock. */ - if (posix_locks_conflict(new_fl, fl)) { + if (posix_locks_conflict(&tfl, fl)) { error = -EAGAIN; if (filp && (filp->f_flags & O_NONBLOCK)) break; @@ -552,12 +614,12 @@ repeat: if (signal_pending(current)) break; error = -EDEADLK; - if (posix_locks_deadlock(new_fl, fl)) + if (posix_locks_deadlock(&tfl, fl)) break; - locks_insert_block(fl, new_fl); - interruptible_sleep_on(&new_fl->fl_wait); - locks_delete_block(new_fl); + locks_insert_block(fl, &tfl); + interruptible_sleep_on(&tfl.fl_wait); + locks_delete_block(fl, &tfl); /* * If we've been sleeping someone might have @@ -569,15 +631,202 @@ repeat: } } unlock_kernel(); - locks_free_lock(new_fl); return error; } +/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX + * style lock. + */ +static int posix_make_lock(struct file *filp, struct file_lock *fl, + struct flock *l) +{ + loff_t start; + + memset(fl, 0, sizeof(*fl)); + + init_waitqueue_head(&fl->fl_wait); + fl->fl_flags = FL_POSIX; + + switch (l->l_type) { + case F_RDLCK: + case F_WRLCK: + case F_UNLCK: + fl->fl_type = l->l_type; + break; + default: + return (0); + } + + switch (l->l_whence) { + case 0: /*SEEK_SET*/ + start = 0; + break; + case 1: /*SEEK_CUR*/ + start = filp->f_pos; + break; + case 2: /*SEEK_END*/ + start = filp->f_dentry->d_inode->i_size; + break; + default: + return (0); + } + + if (((start += l->l_start) < 0) || (l->l_len < 0)) + return (0); + fl->fl_end = start + l->l_len - 1; + if (l->l_len > 0 && fl->fl_end < 0) + return (0); + fl->fl_start = start; /* we record the absolute position */ + if (l->l_len == 0) + fl->fl_end = OFFSET_MAX; + + fl->fl_file = filp; + fl->fl_owner = current->files; + fl->fl_pid = current->pid; + + return (1); +} + +/* Verify a call to flock() and fill in a file_lock structure with + * an appropriate FLOCK lock. + */ +static int flock_make_lock(struct file *filp, struct file_lock *fl, + unsigned int cmd) +{ + memset(fl, 0, sizeof(*fl)); + + init_waitqueue_head(&fl->fl_wait); + + switch (cmd & ~LOCK_NB) { + case LOCK_SH: + fl->fl_type = F_RDLCK; + break; + case LOCK_EX: + fl->fl_type = F_WRLCK; + break; + case LOCK_UN: + fl->fl_type = F_UNLCK; + break; + default: + return (0); + } + + fl->fl_flags = FL_FLOCK; + fl->fl_start = 0; + fl->fl_end = OFFSET_MAX; + fl->fl_file = filp; + fl->fl_owner = NULL; + + return (1); +} + +/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific + * checking before calling the locks_conflict(). + */ +static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) +{ + /* POSIX locks owned by the same process do not conflict with + * each other. + */ + if (!(sys_fl->fl_flags & FL_POSIX) || + locks_same_owner(caller_fl, sys_fl)) + return (0); + + return (locks_conflict(caller_fl, sys_fl)); +} + +/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific + * checking before calling the locks_conflict(). + */ +static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) +{ + /* FLOCK locks referring to the same filp do not conflict with + * each other. + */ + if (!(sys_fl->fl_flags & FL_FLOCK) || + (caller_fl->fl_file == sys_fl->fl_file)) + return (0); + + return (locks_conflict(caller_fl, sys_fl)); +} + +/* Determine if lock sys_fl blocks lock caller_fl. Common functionality + * checks for overlapping locks and shared/exclusive status. + */ +static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) +{ + if (!locks_overlap(caller_fl, sys_fl)) + return (0); + + switch (caller_fl->fl_type) { + case F_RDLCK: + return (sys_fl->fl_type == F_WRLCK); + + case F_WRLCK: + return (1); + + default: + printk("locks_conflict(): impossible lock type - %d\n", + caller_fl->fl_type); + break; + } + return (0); /* This should never happen */ +} + +/* This function tests for deadlock condition before putting a process to + * sleep. The detection scheme is no longer recursive. Recursive was neat, + * but dangerous - we risked stack corruption if the lock data was bad, or + * if the recursion was too deep for any other reason. + * + * We rely on the fact that a task can only be on one lock's wait queue + * at a time. When we find blocked_task on a wait queue we can re-search + * with blocked_task equal to that queue's owner, until either blocked_task + * isn't found, or blocked_task is found on a queue owned by my_task. + * + * Note: the above assumption may not be true when handling lock requests + * from a broken NFS client. But broken NFS clients have a lot more to + * worry about than proper deadlock detection anyway... --okir + */ +static int posix_locks_deadlock(struct file_lock *caller_fl, + struct file_lock *block_fl) +{ + struct file_lock *fl; + struct file_lock *bfl; + void *caller_owner, *blocked_owner; + unsigned int caller_pid, blocked_pid; + + caller_owner = caller_fl->fl_owner; + caller_pid = caller_fl->fl_pid; + blocked_owner = block_fl->fl_owner; + blocked_pid = block_fl->fl_pid; + +next_task: + if (caller_owner == blocked_owner && caller_pid == blocked_pid) + return (1); + for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) { + if (fl->fl_owner == NULL || fl->fl_nextblock == NULL) + continue; + for (bfl = fl->fl_nextblock; bfl != fl; bfl = bfl->fl_nextblock) { + if (bfl->fl_owner == blocked_owner && + bfl->fl_pid == blocked_pid) { + if (fl->fl_owner == caller_owner && + fl->fl_pid == caller_pid) { + return (1); + } + blocked_owner = fl->fl_owner; + blocked_pid = fl->fl_pid; + goto next_task; + } + } + } + return (0); +} + /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks at * the head of the list, but that's secret knowledge known only to the next * two functions. */ -static int flock_lock_file(struct file *filp, unsigned int lock_type, +static int flock_lock_file(struct file *filp, struct file_lock *caller, unsigned int wait) { struct file_lock *fl; @@ -585,14 +834,14 @@ static int flock_lock_file(struct file *filp, unsigned int lock_type, struct file_lock **before; struct inode * inode = filp->f_dentry->d_inode; int error, change; - int unlock = (lock_type == F_UNLCK); + int unlock = (caller->fl_type == F_UNLCK); /* * If we need a new lock, get it in advance to avoid races. */ if (!unlock) { error = -ENOLCK; - new_fl = flock_make_lock(filp, lock_type); + new_fl = locks_alloc_lock(caller); if (!new_fl) goto out; } @@ -602,8 +851,8 @@ search: change = 0; before = &inode->i_flock; while (((fl = *before) != NULL) && (fl->fl_flags & FL_FLOCK)) { - if (filp == fl->fl_file) { - if (lock_type == fl->fl_type) + if (caller->fl_file == fl->fl_file) { + if (caller->fl_type == fl->fl_type) goto out; change = 1; break; @@ -639,7 +888,7 @@ repeat: goto out; locks_insert_block(fl, new_fl); interruptible_sleep_on(&new_fl->fl_wait); - locks_delete_block(new_fl); + locks_delete_block(fl, new_fl); goto repeat; } locks_insert_lock(&inode->i_flock, new_fl); @@ -679,8 +928,8 @@ int posix_lock_file(struct file *filp, struct file_lock *caller, * We may need two file_lock structures for this operation, * so we get them in advance to avoid races. */ - new_fl = locks_alloc_lock(); - new_fl2 = locks_alloc_lock(); + new_fl = locks_empty_lock(); + new_fl2 = locks_empty_lock(); error = -ENOLCK; /* "no luck" */ if (!(new_fl && new_fl2)) goto out; @@ -703,7 +952,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller, goto out; locks_insert_block(fl, caller); interruptible_sleep_on(&caller->fl_wait); - locks_delete_block(caller); + locks_delete_block(fl, caller); goto repeat; } } @@ -809,7 +1058,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller, if (!added) { if (caller->fl_type == F_UNLCK) goto out; - locks_copy_lock(new_fl, caller); + locks_init_lock(new_fl, caller); locks_insert_lock(before, new_fl); new_fl = NULL; } @@ -819,9 +1068,8 @@ int posix_lock_file(struct file *filp, struct file_lock *caller, * so we have to use the second new lock (in this * case, even F_UNLCK may fail!). */ - locks_copy_lock(new_fl2, right); + left = locks_init_lock(new_fl2, right); locks_insert_lock(before, left); - left = new_fl2; new_fl2 = NULL; } right->fl_start = caller->fl_end + 1; @@ -833,288 +1081,101 @@ int posix_lock_file(struct file *filp, struct file_lock *caller, } out: /* - * Free any unused locks. + * Free any unused locks. (They haven't + * ever been used, so we use kfree().) */ if (new_fl) - locks_free_lock(new_fl); + kfree(new_fl); if (new_fl2) - locks_free_lock(new_fl2); + kfree(new_fl2); return error; } -static inline int flock_translate_cmd(int cmd) { - switch (cmd &~ LOCK_NB) { - case LOCK_SH: - return F_RDLCK; - case LOCK_EX: - return F_WRLCK; - case LOCK_UN: - return F_UNLCK; - } - return -EINVAL; -} - -/* flock() system call entry point. Apply a FL_FLOCK style lock to - * an open file descriptor. +/* + * Allocate an empty lock structure. We can use GFP_KERNEL now that + * all allocations are done in advance. */ -asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) +static struct file_lock *locks_empty_lock(void) { - struct file *filp; - int error, type; - - error = -EBADF; - filp = fget(fd); - if (!filp) - goto out; - - error = flock_translate_cmd(cmd); - if (error < 0) - goto out_putf; - type = error; - - error = -EBADF; - if ((type != F_UNLCK) && !(filp->f_mode & 3)) - goto out_putf; - - lock_kernel(); - error = flock_lock_file(filp, type, - (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); - unlock_kernel(); - -out_putf: - fput(filp); -out: - return error; + /* Okay, let's make a new file_lock structure... */ + return ((struct file_lock *) kmalloc(sizeof(struct file_lock), + GFP_KERNEL)); } -/* Report the first existing lock that would conflict with l. - * This implements the F_GETLK command of fcntl(). +/* + * Initialize a new lock from an existing file_lock structure. */ -int fcntl_getlk(unsigned int fd, struct flock *l) +static struct file_lock *locks_init_lock(struct file_lock *new, + struct file_lock *fl) { - struct file *filp; - struct file_lock *fl, *file_lock = locks_alloc_lock(); - struct flock flock; - int error; - - error = -EFAULT; - if (copy_from_user(&flock, l, sizeof(flock))) - goto out; - error = -EINVAL; - if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) - goto out; - - error = -EBADF; - filp = fget(fd); - if (!filp) - goto out; - - if (!posix_make_lock(filp, file_lock, &flock)) - goto out_putf; - - if (filp->f_op->lock) { - error = filp->f_op->lock(filp, F_GETLK, file_lock); - if (error < 0) - goto out_putf; - else if (error == LOCK_USE_CLNT) - /* Bypass for NFS with no locking - 2.0.36 compat */ - fl = posix_test_lock(filp, file_lock); - else - fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock); - } else { - fl = posix_test_lock(filp, file_lock); + if (new) { + memset(new, 0, sizeof(*new)); + new->fl_owner = fl->fl_owner; + new->fl_pid = fl->fl_pid; + init_waitqueue_head(&new->fl_wait); + new->fl_file = fl->fl_file; + new->fl_flags = fl->fl_flags; + new->fl_type = fl->fl_type; + new->fl_start = fl->fl_start; + new->fl_end = fl->fl_end; + new->fl_notify = fl->fl_notify; + new->fl_insert = fl->fl_insert; + new->fl_remove = fl->fl_remove; + new->fl_u = fl->fl_u; } - - flock.l_type = F_UNLCK; - if (fl != NULL) { - flock.l_pid = fl->fl_pid; - flock.l_start = fl->fl_start; - flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : - fl->fl_end - fl->fl_start + 1; - flock.l_whence = 0; - flock.l_type = fl->fl_type; - } - error = -EFAULT; - if (!copy_to_user(l, &flock, sizeof(flock))) - error = 0; - -out_putf: - fput(filp); -out: - locks_free_lock(file_lock); - return error; + return new; } -/* Apply the lock described by l to an open file descriptor. - * This implements both the F_SETLK and F_SETLKW commands of fcntl(). +/* Insert file lock fl into an inode's lock list at the position indicated + * by pos. At the same time add the lock to the global file lock list. */ -int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) -{ - struct file *filp; - struct file_lock *file_lock = locks_alloc_lock(); - struct flock flock; - struct inode *inode; - int error; - - /* - * This might block, so we do it before checking the inode. - */ - error = -EFAULT; - if (copy_from_user(&flock, l, sizeof(flock))) - goto out; - - /* Get arguments and validate them ... - */ - - error = -EBADF; - filp = fget(fd); - if (!filp) - goto out; - - error = -EINVAL; - inode = filp->f_dentry->d_inode; - - /* Don't allow mandatory locks on files that may be memory mapped - * and shared. - */ - if (IS_MANDLOCK(inode) && - (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { - struct vm_area_struct *vma; - struct address_space *mapping = inode->i_mapping; - spin_lock(&mapping->i_shared_lock); - for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) { - if (!(vma->vm_flags & VM_MAYSHARE)) - continue; - spin_unlock(&mapping->i_shared_lock); - error = -EAGAIN; - goto out_putf; - } - spin_unlock(&mapping->i_shared_lock); - } - - error = -EINVAL; - if (!posix_make_lock(filp, file_lock, &flock)) - goto out_putf; - - error = -EBADF; - switch (flock.l_type) { - case F_RDLCK: - if (!(filp->f_mode & FMODE_READ)) - goto out_putf; - break; - case F_WRLCK: - if (!(filp->f_mode & FMODE_WRITE)) - goto out_putf; - break; - case F_UNLCK: - break; - case F_SHLCK: - case F_EXLCK: -#ifdef __sparc__ -/* warn a bit for now, but don't overdo it */ +static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) { - static int count = 0; - if (!count) { - count=1; - printk(KERN_WARNING - "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n", - current->pid, current->comm); - } -} - if (!(filp->f_mode & 3)) - goto out_putf; - break; -#endif - default: - error = -EINVAL; - goto out_putf; - } + fl->fl_nextlink = file_lock_table; + fl->fl_prevlink = NULL; + if (file_lock_table != NULL) + file_lock_table->fl_prevlink = fl; + file_lock_table = fl; + fl->fl_next = *pos; /* insert into file's list */ + *pos = fl; - if (filp->f_op->lock != NULL) { - error = filp->f_op->lock(filp, cmd, file_lock); - if (error < 0) - goto out_putf; - } - error = posix_lock_file(filp, file_lock, cmd == F_SETLKW); + if (fl->fl_insert) + fl->fl_insert(fl); -out_putf: - fput(filp); -out: - locks_free_lock(file_lock); - return error; + return; } -/* - * This function is called when the file is being removed - * from the task's fd array. +/* Delete a lock and free it. + * First remove our lock from the active lock lists. Then call + * locks_wake_up_blocks() to wake up processes that are blocked + * waiting for this lock. Finally free the lock structure. */ -void locks_remove_posix(struct file *filp, fl_owner_t owner) +static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait) { - struct inode * inode = filp->f_dentry->d_inode; - struct file_lock *fl; - struct file_lock **before; + struct file_lock *thisfl; + struct file_lock *prevfl; + struct file_lock *nextfl; + + thisfl = *thisfl_p; + *thisfl_p = thisfl->fl_next; - /* - * For POSIX locks we free all locks on this file for the given task. - */ -repeat: - before = &inode->i_flock; - while ((fl = *before) != NULL) { - if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) { - locks_delete_lock(before, 0); - goto repeat; - } - before = &fl->fl_next; - } -} + prevfl = thisfl->fl_prevlink; + nextfl = thisfl->fl_nextlink; -/* - * This function is called on the last close of an open file. - */ -void locks_remove_flock(struct file *filp) -{ - struct inode * inode = filp->f_dentry->d_inode; - struct file_lock file_lock, *fl; - struct file_lock **before; + if (nextfl != NULL) + nextfl->fl_prevlink = prevfl; -repeat: - before = &inode->i_flock; - while ((fl = *before) != NULL) { - if ((fl->fl_flags & FL_FLOCK) && fl->fl_file == filp) { - int (*lock)(struct file *, int, struct file_lock *); - lock = NULL; - if (filp->f_op) - lock = filp->f_op->lock; - if (lock) { - file_lock = *fl; - file_lock.fl_type = F_UNLCK; - } - locks_delete_lock(before, 0); - if (lock) { - lock(filp, F_SETLK, &file_lock); - /* List may have changed: */ - goto repeat; - } - continue; - } - before = &fl->fl_next; - } -} + if (prevfl != NULL) + prevfl->fl_nextlink = nextfl; + else + file_lock_table = nextfl; -/* The following two are for the benefit of lockd. - */ -void -posix_block_lock(struct file_lock *blocker, struct file_lock *waiter) -{ - lock_kernel(); - locks_insert_block(blocker, waiter); - unlock_kernel(); -} + if (thisfl->fl_remove) + thisfl->fl_remove(thisfl); + + locks_wake_up_blocks(thisfl, wait); + locks_free_lock(thisfl); -void -posix_unblock_lock(struct file_lock *waiter) -{ - locks_delete_block(waiter); return; } @@ -1141,8 +1202,8 @@ static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) kdevname(inode->i_dev), inode->i_ino, (long long)fl->fl_start, (long long)fl->fl_end); sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n", - (long)fl, (long)fl->fl_link.prev, (long)fl->fl_link.next, - (long)fl->fl_next, (long)fl->fl_block.next); + (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink, + (long)fl->fl_next, (long)fl->fl_nextblock); } static void move_lock_status(char **p, off_t* pos, off_t offset) @@ -1169,43 +1230,35 @@ static void move_lock_status(char **p, off_t* pos, off_t offset) int get_locks_status(char *buffer, char **start, off_t offset, int length) { - struct list_head *tmp; + struct file_lock *fl; + struct file_lock *bfl; char *q = buffer; off_t pos = 0; - int i = 0; + int i; - lock_kernel(); - list_for_each(tmp, &file_lock_list) { - struct list_head *btmp; - struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); - lock_get_status(q, fl, ++i, ""); + for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) { + lock_get_status(q, fl, i, ""); move_lock_status(&q, &pos, offset); if(pos >= offset+length) goto done; - list_for_each(btmp, &fl->fl_block) { - struct file_lock *bfl = list_entry(btmp, - struct file_lock, fl_block); + if ((bfl = fl->fl_nextblock) == NULL) + continue; + do { lock_get_status(q, bfl, i, " ->"); move_lock_status(&q, &pos, offset); if(pos >= offset+length) goto done; - } + } while ((bfl = bfl->fl_nextblock) != fl); } done: - unlock_kernel(); *start = buffer; if(q-buffer < length) return (q-buffer); return length; } -void __init filelock_init(void) -{ - filelock_cache = kmem_cache_create("file lock cache", - sizeof(struct file_lock), 0, 0, init_once, NULL); - if (!filelock_cache) - panic("cannot create file lock slab cache"); -} + + diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index ca30b7753..075574876 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c @@ -276,13 +276,16 @@ struct inode * minix_new_inode(const struct inode * dir, int * error) mark_inode_dirty(inode); unlock_super(sb); +printk("m_n_i: allocated inode "); if(DQUOT_ALLOC_INODE(sb, inode)) { +printk("fails quota test\n"); sb->dq_op->drop(inode); inode->i_nlink = 0; iput(inode); *error = -EDQUOT; return NULL; } +printk("is within quota\n"); *error = 0; return inode; diff --git a/fs/minix/fsync.c b/fs/minix/fsync.c index 96e1ffa86..30794d27a 100644 --- a/fs/minix/fsync.c +++ b/fs/minix/fsync.c @@ -329,7 +329,7 @@ static int V2_minix_sync_file(struct inode * inode, struct file * file) * NULL */ -int minix_sync_file(struct file * file, struct dentry *dentry, int datasync) +int minix_sync_file(struct file * file, struct dentry *dentry) { struct inode *inode = dentry->d_inode; diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 7b6850e6f..6ddc278aa 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -28,7 +28,7 @@ #include <linux/minix_fs.h> static void minix_read_inode(struct inode * inode); -static void minix_write_inode(struct inode * inode, int); +static void minix_write_inode(struct inode * inode); static int minix_statfs(struct super_block *sb, struct statfs *buf); static int minix_remount (struct super_block * sb, int * flags, char * data); @@ -1232,7 +1232,7 @@ static struct buffer_head *minix_update_inode(struct inode *inode) return V2_minix_update_inode(inode); } -static void minix_write_inode(struct inode * inode, int unused) +static void minix_write_inode(struct inode * inode) { struct buffer_head *bh; diff --git a/fs/namei.c b/fs/namei.c index 96ae55768..501000381 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -191,35 +191,21 @@ int permission(struct inode * inode,int mask) * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist * > 0: (i_writecount) users are writing to the file. * - * Normally we operate on that counter with atomic_{inc,dec} and it's safe - * except for the cases where we don't hold i_writecount yet. Then we need to - * use {get,deny}_write_access() - these functions check the sign and refuse - * to do the change if sign is wrong. Exclusion between them is provided by - * spinlock (arbitration_lock) and I'll rip the second arsehole to the first - * who will try to move it in struct inode - just leave it here. + * WARNING: as soon as we will move get_write_access(), do_mmap() or + * prepare_binfmt() out of the big lock we will need a spinlock protecting + * the checks in all 3. For the time being it is not needed. */ -static spinlock_t arbitration_lock = SPIN_LOCK_UNLOCKED; int get_write_access(struct inode * inode) { - spin_lock(&arbitration_lock); - if (atomic_read(&inode->i_writecount) < 0) { - spin_unlock(&arbitration_lock); + if (atomic_read(&inode->i_writecount) < 0) return -ETXTBSY; - } atomic_inc(&inode->i_writecount); - spin_unlock(&arbitration_lock); return 0; } -int deny_write_access(struct file * file) + +void put_write_access(struct inode * inode) { - spin_lock(&arbitration_lock); - if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) { - spin_unlock(&arbitration_lock); - return -ETXTBSY; - } - atomic_dec(&file->f_dentry->d_inode->i_writecount); - spin_unlock(&arbitration_lock); - return 0; + atomic_dec(&inode->i_writecount); } void path_release(struct nameidata *nd) @@ -351,34 +337,7 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) { return __follow_down(mnt,dentry); } - -static inline void follow_dotdot(struct nameidata *nd) -{ - while(1) { - struct vfsmount *parent; - struct dentry *dentry; - if (nd->dentry == current->fs->root && - nd->mnt == current->fs->rootmnt) { - break; - } - if (nd->dentry != nd->mnt->mnt_root) { - dentry = dget(nd->dentry->d_parent); - dput(nd->dentry); - nd->dentry = dentry; - break; - } - parent=nd->mnt->mnt_parent; - if (parent == nd->mnt) { - break; - } - mntget(parent); - dentry=dget(nd->mnt->mnt_mountpoint); - dput(nd->dentry); - nd->dentry = dentry; - mntput(nd->mnt); - nd->mnt = parent; - } -} + /* * Name resolution. * @@ -444,7 +403,19 @@ int path_walk(const char * name, struct nameidata *nd) case 2: if (this.name[1] != '.') break; - follow_dotdot(nd); + while (1) { + if (nd->dentry == current->fs->root && + nd->mnt == current->fs->rootmnt) + break; + if (nd->dentry != nd->mnt->mnt_root) { + dentry = dget(nd->dentry->d_parent); + dput(nd->dentry); + nd->dentry = dentry; + break; + } + if (!__follow_up(&nd->mnt, &nd->dentry)) + break; + } inode = nd->dentry->d_inode; /* fallthrough */ case 1: @@ -512,7 +483,19 @@ last_component: case 2: if (this.name[1] != '.') break; - follow_dotdot(nd); + while (1) { + if (nd->dentry == current->fs->root && + nd->mnt == current->fs->rootmnt) + break; + if (nd->dentry != nd->mnt->mnt_root) { + dentry = dget(nd->dentry->d_parent); + dput(nd->dentry); + nd->dentry = dentry; + break; + } + if (!__follow_up(&nd->mnt, &nd->dentry)) + break; + } inode = nd->dentry->d_inode; /* fallthrough */ case 1: @@ -788,6 +771,8 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) int error; if (!victim->d_inode || victim->d_parent->d_inode != dir) return -ENOENT; + if (IS_DEADDIR(dir)) + return -ENOENT; error = permission(dir,MAY_WRITE | MAY_EXEC); if (error) return error; @@ -801,6 +786,8 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) return -ENOTDIR; if (IS_ROOT(victim)) return -EBUSY; + if (d_mountpoint(victim)) + return -EBUSY; } else if (S_ISDIR(victim->d_inode->i_mode)) return -EISDIR; return 0; @@ -930,22 +917,6 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) error = -EEXIST; if (flag & O_EXCL) goto exit_dput; - if (flag & O_NOFOLLOW) { - error = -ELOOP; - if (dentry->d_inode->i_op && - dentry->d_inode->i_op->follow_link) - goto exit_dput; - if (d_mountpoint(dentry)) - goto exit_dput; - goto got_it; - } - /* Check mountpoints - it may be a binding on file. */ - while (d_mountpoint(dentry) && - __follow_down(&nd->mnt, &dentry)) - ; - error = -ENOENT; - if (!dentry->d_inode) - goto exit_dput; if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link) { /* @@ -959,7 +930,6 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) return error; dentry = nd->dentry; } else { - got_it: dput(nd->dentry); nd->dentry = dentry; } @@ -992,10 +962,6 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) goto exit; - error = -EOPNOTSUPP; - if (S_ISSOCK(inode->i_mode)) - goto exit; - error = permission(inode,acc_mode); if (error) goto exit; @@ -1247,15 +1213,9 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) double_down(&dir->i_zombie, &dentry->d_inode->i_zombie); d_unhash(dentry); - if (IS_DEADDIR(dir)) - error = -ENOENT; - else if (d_mountpoint(dentry)) - error = -EBUSY; - else { - error = dir->i_op->rmdir(dir, dentry); - if (!error) - dentry->d_inode->i_flags |= S_DEAD; - } + error = dir->i_op->rmdir(dir, dentry); + if (!error) + dentry->d_inode->i_flags |= S_DEAD; double_up(&dir->i_zombie, &dentry->d_inode->i_zombie); if (!error) d_delete(dentry); @@ -1315,13 +1275,9 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) error = -EPERM; if (dir->i_op && dir->i_op->unlink) { DQUOT_INIT(dir); - if (d_mountpoint(dentry)) - error = -EBUSY; - else { - error = dir->i_op->unlink(dir, dentry); - if (!error) - d_delete(dentry); - } + error = dir->i_op->unlink(dir, dentry); + if (!error) + d_delete(dentry); } } up(&dir->i_zombie); @@ -1599,12 +1555,7 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, } else double_down(&old_dir->i_zombie, &new_dir->i_zombie); - if (IS_DEADDIR(old_dir)||IS_DEADDIR(new_dir)) - error = -ENOENT; - else if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) - error = -EBUSY; - else - error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); + error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); if (target) { if (!error) target->i_flags |= S_DEAD; @@ -1652,10 +1603,7 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, DQUOT_INIT(old_dir); DQUOT_INIT(new_dir); double_down(&old_dir->i_zombie, &new_dir->i_zombie); - if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) - error = -EBUSY; - else - error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); + error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); double_up(&old_dir->i_zombie, &new_dir->i_zombie); if (error) return error; diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 11694e79b..55daea198 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -973,7 +973,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry) /* * Check whether to close the file ... */ - if (inode) { + if (inode && NCP_FINFO(inode)->opened) { PPRINTK("ncp_unlink: closing file\n"); ncp_make_closed(inode); } @@ -982,7 +982,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry) #ifdef CONFIG_NCPFS_STRONG /* 9C is Invalid path.. It should be 8F, 90 - read only, but it is not :-( */ - if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */ + if (error == 0x9C && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */ error = ncp_force_unlink(dir, dentry); } #endif @@ -1051,7 +1051,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name, new_dir, __new_name); #ifdef CONFIG_NCPFS_STRONG - if ((error == 0x90 || error == 0x8B || error == -EACCES) && + if ((error == 0x90 || error == -EACCES) && server->m.flags & NCP_MOUNT_STRONG) { /* RO */ error = ncp_force_rename(old_dir, old_dentry, __old_name, new_dir, new_dentry, __new_name); diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 3442c3f9f..6f8fd2d63 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -26,7 +26,7 @@ static inline unsigned int min(unsigned int a, unsigned int b) return a < b ? a : b; } -static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync) +static int ncp_fsync(struct file *file, struct dentry *dentry) { return 0; } @@ -46,12 +46,12 @@ int ncp_make_open(struct inode *inode, int right) } DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %u\n", - atomic_read(&NCP_FINFO(inode)->opened), + NCP_FINFO(inode)->opened, NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum); error = -EACCES; - down(&NCP_FINFO(inode)->open_sem); - if (!atomic_read(&NCP_FINFO(inode)->opened)) { + lock_super(inode->i_sb); + if (!NCP_FINFO(inode)->opened) { struct ncp_entry_info finfo; int result; @@ -88,18 +88,15 @@ int ncp_make_open(struct inode *inode, int right) */ update: ncp_update_inode(inode, &finfo); - atomic_set(&NCP_FINFO(inode)->opened, 1); } access = NCP_FINFO(inode)->access; PPRINTK("ncp_make_open: file open, access=%x\n", access); - if (access == right || access == O_RDWR) { - atomic_inc(&NCP_FINFO(inode)->opened); + if (access == right || access == O_RDWR) error = 0; - } out_unlock: - up(&NCP_FINFO(inode)->open_sem); + unlock_super(inode->i_sb); out: return error; } @@ -156,7 +153,7 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos) freelen = ncp_read_bounce_size(bufsize); freepage = kmalloc(freelen, GFP_NFS); if (!freepage) - goto outrel; + goto out; error = 0; /* First read in as much as possible for each bufsize. */ while (already_read < count) { @@ -169,8 +166,9 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos) pos, to_read, buf, &read_this_time, freepage, freelen); if (error) { - error = -EIO; /* NW errno -> Linux errno */ - break; + kfree(freepage); + error = -EIO; /* This is not exact, i know.. */ + goto out; } pos += read_this_time; buf += read_this_time; @@ -190,8 +188,6 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos) DPRINTK("ncp_file_read: exit %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); -outrel: - ncp_inode_close(inode); out: return already_read ? already_read : error; } @@ -240,10 +236,8 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) already_written = 0; bouncebuffer = kmalloc(bufsize, GFP_NFS); - if (!bouncebuffer) { - errno = -EIO; /* -ENOMEM */ - goto outrel; - } + if (!bouncebuffer) + return -EIO; /* -ENOMEM */ while (already_written < count) { int written_this_time; size_t to_write = min(bufsize - (pos % bufsize), @@ -277,15 +271,15 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) } DPRINTK("ncp_file_write: exit %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); -outrel: - ncp_inode_close(inode); out: return already_written ? already_written : errno; } static int ncp_release(struct inode *inode, struct file *file) { - if (ncp_make_closed(inode)) { - DPRINTK("ncp_release: failed to close\n"); + if (NCP_FINFO(inode)->opened) { + if (ncp_make_closed(inode)) { + DPRINTK("ncp_release: failed to close\n"); + } } return 0; } diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index cff9649f5..e885aed47 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -61,6 +61,7 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo) #ifdef CONFIG_NCPFS_STRONG NCP_FINFO(inode)->nwattr = nwinfo->i.attributes; #endif + NCP_FINFO(inode)->opened = nwinfo->opened; NCP_FINFO(inode)->access = nwinfo->access; NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle; memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle, @@ -75,7 +76,7 @@ void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo) struct nw_info_struct *nwi = &nwinfo->i; struct ncp_server *server = NCP_SERVER(inode); - if (!atomic_read(&NCP_FINFO(inode)->opened)) { + if (!NCP_FINFO(inode)->opened) { #ifdef CONFIG_NCPFS_STRONG NCP_FINFO(inode)->nwattr = nwi->attributes; #endif @@ -215,9 +216,6 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info) inode = get_empty_inode(); if (inode) { - init_MUTEX(&NCP_FINFO(inode)->open_sem); - atomic_set(&NCP_FINFO(inode)->opened, info->opened); - inode->i_sb = sb; inode->i_dev = sb->s_dev; inode->i_ino = info->ino; @@ -247,7 +245,7 @@ ncp_delete_inode(struct inode *inode) DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino); } - if (ncp_make_closed(inode) != 0) { + if (NCP_FINFO(inode)->opened && ncp_make_closed(inode) != 0) { /* We can't do anything but complain. */ printk(KERN_ERR "ncp_delete_inode: could not close\n"); } @@ -320,6 +318,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent) sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = NCP_SUPER_MAGIC; + sb->s_dev = dev; sb->s_op = &ncp_sops; server = NCP_SBP(sb); @@ -677,7 +676,6 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) /* According to ndir, the changes only take effect after closing the file */ - ncp_inode_close(inode); result = ncp_make_closed(inode); if (!result) vmtruncate(inode, attr->ia_size); diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 24e616396..26c95fc8f 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -335,12 +335,18 @@ int ncp_ioctl(struct inode *inode, struct file *filp, { return result; } - result = -EIO; if (!ncp_conn_valid(server)) - goto outrel; - result = -EISDIR; + { + return -EIO; + } if (!S_ISREG(inode->i_mode)) - goto outrel; + { + return -EISDIR; + } + if (!NCP_FINFO(inode)->opened) + { + return -EBADFD; + } if (rqdata.cmd == NCP_LOCK_CLEAR) { result = ncp_ClearPhysicalRecord(NCP_SERVER(inode), @@ -367,8 +373,6 @@ int ncp_ioctl(struct inode *inode, struct file *filp, rqdata.timeout); if (result > 0) result = -EAGAIN; } -outrel: - ncp_inode_close(inode); return result; } #endif /* CONFIG_NCPFS_IOCTL_LOCKING */ diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 08d28d895..752ae1e1e 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -82,7 +82,6 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area, break; } } - ncp_inode_close(inode); } diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index 0353882b9..73afd107a 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -221,23 +221,20 @@ ncp_close_file(struct ncp_server *server, const char *file_id) return result; } +/* + * Called with the superblock locked. + */ int ncp_make_closed(struct inode *inode) { int err; + NCP_FINFO(inode)->opened = 0; + err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle); - err = 0; - down(&NCP_FINFO(inode)->open_sem); - if (atomic_read(&NCP_FINFO(inode)->opened) == 1) { - atomic_set(&NCP_FINFO(inode)->opened, 0); - err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle); - - if (!err) - PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n", - NCP_FINFO(inode)->volNumber, - NCP_FINFO(inode)->dirEntNum, err); - } - up(&NCP_FINFO(inode)->open_sem); + if (!err) + PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n", + NCP_FINFO(inode)->volNumber, + NCP_FINFO(inode)->dirEntNum, err); return err; } @@ -616,8 +613,7 @@ int ncp_open_create_file_or_subdir(struct ncp_server *server, if ((result = ncp_request(server, 87)) != 0) goto out; - if (!(create_attributes & aDIR)) - target->opened = 1; + target->opened = 1; target->server_file_handle = ncp_reply_dword(server, 0); target->open_create_action = ncp_reply_byte(server, 4); diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 31797a3c3..8b33a5c2e 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -57,10 +57,6 @@ int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16, int ncp_write_kernel(struct ncp_server *, const char *, __u32, __u16, const char *, int *); -static inline void ncp_inode_close(struct inode *inode) { - atomic_dec(&NCP_FINFO(inode)->opened); -} - int ncp_obtain_info(struct ncp_server *server, struct inode *, char *, struct nw_info_struct *target); int ncp_lookup_volume(struct ncp_server *, char *, struct nw_info_struct *); diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c index 0962593da..46925eb6d 100644 --- a/fs/ncpfs/symlink.c +++ b/fs/ncpfs/symlink.c @@ -50,6 +50,10 @@ static int ncp_symlink_readpage(struct file *file, struct page *page) char *link; char *buf = (char*)kmap(page); + error = -EIO; + if (ncp_make_open(inode,O_RDONLY)) + goto fail; + error = -ENOMEM; for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) { if (cnt > 10) @@ -57,22 +61,20 @@ static int ncp_symlink_readpage(struct file *file, struct page *page) schedule(); } - if (ncp_make_open(inode,O_RDONLY)) - goto failEIO; - error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle, 0,NCP_MAX_SYMLINK_SIZE,link,&length); - ncp_inode_close(inode); - /* Close file handle if no other users... */ - ncp_make_closed(inode); - if (error) - goto failEIO; - + if (error) { + kfree(link); + goto fail; + } if (length<NCP_MIN_SYMLINK_SIZE || ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 || - ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) - goto failEIO; + ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) { + error = -EIO; + kfree(link); + goto fail; + } len = NCP_MAX_SYMLINK_SIZE; error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link+8, length-8, 0); @@ -84,9 +86,6 @@ static int ncp_symlink_readpage(struct file *file, struct page *page) UnlockPage(page); return 0; -failEIO: - error = -EIO; - kfree(link); fail: SetPageError(page); kunmap(page); @@ -121,15 +120,13 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL) return -ENOMEM; - err = -EIO; - if (ncp_create_new(dir,dentry,0,aSHARED|aHIDDEN)) - goto failfree; + if (ncp_create_new(dir,dentry,0,aSHARED|aHIDDEN)) { + kfree(link); + return -EIO; + } inode=dentry->d_inode; - if (ncp_make_open(inode, O_WRONLY)) - goto failfree; - ((__u32 *)link)[0]=NCP_SYMLINK_MAGIC0; ((__u32 *)link)[1]=NCP_SYMLINK_MAGIC1; @@ -137,26 +134,19 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { symlink can point out of ncp filesystem */ length += 1; err = ncp_io2vol(NCP_SERVER(inode),link+8,&length,symname,length-1,0); - if (err) - goto fail; + if (err) { + kfree(link); + return err; + } if(ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, 0, length+8, link, &i) || i!=length+8) { - err = -EIO; - goto fail; + kfree(link); + return -EIO; } - ncp_inode_close(inode); - ncp_make_closed(inode); kfree(link); return 0; - -fail: - ncp_inode_close(inode); - ncp_make_closed(inode); -failfree: - kfree(link); - return err; } #endif diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 4225bfc86..62b37c8cf 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -38,7 +38,7 @@ static int nfs_file_mmap(struct file *, struct vm_area_struct *); static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *); static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *); static int nfs_file_flush(struct file *); -static int nfs_fsync(struct file *, struct dentry *dentry, int); +static int nfs_fsync(struct file *, struct dentry *dentry); struct file_operations nfs_file_operations = { read: nfs_file_read, @@ -123,7 +123,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) * whether any write errors occurred for this process. */ static int -nfs_fsync(struct file *file, struct dentry *dentry, int datasync) +nfs_fsync(struct file *file, struct dentry *dentry) { struct inode *inode = dentry->d_inode; int status; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index c2607ff2e..c4e456185 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -218,7 +218,7 @@ static struct { }; #define CMD_MAX (sizeof(sizes)/sizeof(sizes[0])-1) -int +long asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp) { struct nfsctl_arg * argp = opaque_argp; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index a2b2b4971..fb3b32f8d 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -83,10 +83,7 @@ nfsd_svc(unsigned short port, int nrservs) if (error < 0) goto failure; -#if CONFIG_NFSD_TCP - /* This is developer-only at the moment, - * there are untracked bugs as of 2.4.0-test1-ac11 - */ +#if 0 /* Don't even pretend that TCP works. It doesn't. */ error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); if (error < 0) goto failure; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 601549ccc..40f1ab85a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -314,7 +314,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) if (err) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) - write_inode_now(inode, 0); + write_inode_now(inode); err = 0; /* Don't unlock inode; the nfssvc_release functions are supposed @@ -512,7 +512,7 @@ nfsd_sync(struct file *filp) { dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name); down(&filp->f_dentry->d_inode->i_sem); - filp->f_op->fsync(filp, filp->f_dentry,0); + filp->f_op->fsync(filp, filp->f_dentry); up(&filp->f_dentry->d_inode->i_sem); } @@ -520,10 +520,10 @@ void nfsd_sync_dir(struct dentry *dp) { struct inode *inode = dp->d_inode; - int (*fsync) (struct file *, struct dentry *, int); + int (*fsync) (struct file *, struct dentry *); if (inode->i_fop && (fsync = inode->i_fop->fsync)) { - fsync(NULL, dp, 0); + fsync(NULL, dp); } } @@ -891,7 +891,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, if (EX_ISSYNC(fhp->fh_export)) { nfsd_sync_dir(dentry); - write_inode_now(dchild->d_inode, 0); + write_inode_now(dchild->d_inode); } @@ -1118,7 +1118,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | S_IFLNK; err = notify_change(dnew, iap); if (!err && EX_ISSYNC(fhp->fh_export)) - write_inode_now(dentry->d_inode, 0); + write_inode_now(dentry->d_inode); } } } else @@ -1178,7 +1178,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, if (!err) { if (EX_ISSYNC(ffhp->fh_export)) { nfsd_sync_dir(ddir); - write_inode_now(dest, 0); + write_inode_now(dest); } } else { if (err == -EXDEV && rqstp->rq_vers == 2) diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index 9e7ab2eaf..6f0e188d1 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile @@ -3,7 +3,7 @@ O_TARGET := ntfs.o O_OBJS := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o M_OBJS := $(O_TARGET) -EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"000607\" +EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"000502\" include $(TOPDIR)/Rules.make diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c index 8ec377e0a..e0649ec7b 100644 --- a/fs/ntfs/fs.c +++ b/fs/ntfs/fs.c @@ -80,7 +80,7 @@ ntfs_read(struct file * filp, char *buf, size_t count, loff_t *off) io.param=buf; io.size=count; error=ntfs_read_attr(ino,ino->vol->at_data,NULL,*off,&io); - if(error && !io.size)return -error; + if(error)return -error; *off+=io.size; return io.size; @@ -707,7 +707,7 @@ static void ntfs_read_inode(struct inode* inode) #ifdef CONFIG_NTFS_RW static void -ntfs_write_inode (struct inode *ino, int unused) +ntfs_write_inode (struct inode *ino) { ntfs_debug (DEBUG_LINUX, "ntfs:write inode %x\n", ino->i_ino); ntfs_update_inode (NTFS_LINO2NINO (ino)); diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 631323769..b0941569b 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -312,9 +312,9 @@ static void devfs_register_partition (struct gendisk *dev, int minor, int part) devfs_flags |= DEVFS_FL_REMOVABLE; sprintf (devname, "part%d", part); dev->part[minor + part].de = - devfs_register (dir, devname, 0, devfs_flags, + devfs_register (dir, devname, devfs_flags, dev->major, minor + part, - S_IFBLK | S_IRUSR | S_IWUSR, 0, 0, + S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL); } @@ -350,8 +350,8 @@ static void devfs_register_disc (struct gendisk *dev, int minor) devfs_mk_symlink (devfs_handle, symlink, 0, DEVFS_FL_DEFAULT, dirname + pos, 0, &slave, NULL); dev->part[minor].de = - devfs_register (dir, "disc", 4, devfs_flags, dev->major, minor, - S_IFBLK | S_IRUSR | S_IWUSR, 0, 0, dev->fops,NULL); + devfs_register (dir, "disc", devfs_flags, dev->major, minor, + S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL); devfs_auto_unregister (dev->part[minor].de, slave); if (!dev->de_arr) devfs_auto_unregister (slave, dir); @@ -607,8 +607,6 @@ static struct super_block * pipefs_read_super(struct super_block *sb, void *data root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_uid = root->i_gid = 0; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; - root->i_sb = sb; - root->i_dev = sb->s_dev; sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = PIPEFS_MAGIC; diff --git a/fs/proc/base.c b/fs/proc/base.c index fa7ff052d..fb63722d5 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -303,7 +303,7 @@ static struct file_operations proc_info_file_operations = { }; #define MAY_PTRACE(p) \ -(p==current||(p->p_pptr==current&&(p->ptrace&PT_PTRACED)&&p->state==TASK_STOPPED)) +(p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED)) static ssize_t mem_read(struct file * file, char * buf, size_t count, loff_t *ppos) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index dc6f96b17..9c7270070 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -44,7 +44,7 @@ static struct file_operations proc_file_operations = { #endif /* 4K page size but our output routines use some slack for overruns */ -#define PROC_BLOCK_SIZE (3*1024) +#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) static ssize_t proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index f2503b765..9afe2d67c 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -325,14 +325,14 @@ static int kstat_read_proc(char *page, char **start, off_t off, for (major = 0; major < DK_MAX_MAJOR; major++) { for (disk = 0; disk < DK_MAX_DISK; disk++) { - int active = kstat.dk_drive[major][disk] + + int active = kstat.dk_drive_rio[major][disk] + kstat.dk_drive_rblk[major][disk] + + kstat.dk_drive_wio[major][disk] + kstat.dk_drive_wblk[major][disk]; if (active) len += sprintf(page + len, - "(%u,%u):(%u,%u,%u,%u,%u) ", + "(%u,%u):(%u,%u,%u,%u) ", major, disk, - kstat.dk_drive[major][disk], kstat.dk_drive_rio[major][disk], kstat.dk_drive_rblk[major][disk], kstat.dk_drive_wio[major][disk], diff --git a/fs/qnx4/fsync.c b/fs/qnx4/fsync.c index e8f079c24..e90291f03 100644 --- a/fs/qnx4/fsync.c +++ b/fs/qnx4/fsync.c @@ -147,7 +147,7 @@ static int sync_dindirect(struct inode *inode, unsigned short *diblock, return err; } -int qnx4_sync_file(struct file *file, struct dentry *dentry, int datasync) +int qnx4_sync_file(struct file *file, struct dentry *dentry) { struct inode *inode = dentry->d_inode; int wait, err = 0; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 0785ee368..60393eb91 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -73,7 +73,7 @@ static void qnx4_write_super(struct super_block *sb) sb->s_dirt = 0; } -static void qnx4_write_inode(struct inode *inode, int unused) +static void qnx4_write_inode(struct inode *inode) { struct qnx4_inode_entry *raw_inode; int block, ino; @@ -340,6 +340,7 @@ static struct super_block *qnx4_read_super(struct super_block *s, set_blocksize(dev, QNX4_BLOCK_SIZE); s->s_blocksize = QNX4_BLOCK_SIZE; s->s_blocksize_bits = QNX4_BLOCK_SIZE_BITS; + s->s_dev = dev; /* Check the boot signature. Since the qnx4 code is dangerous, we should leave as quickly as possible diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 2a1a7423d..f87d30e0b 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -22,14 +22,13 @@ * caches is sufficient. */ - #include <linux/module.h> #include <linux/fs.h> #include <linux/pagemap.h> #include <linux/init.h> #include <linux/string.h> #include <linux/locks.h> -#include <linux/highmem.h> + #include <asm/uaccess.h> /* some random number */ @@ -66,8 +65,7 @@ static struct dentry * ramfs_lookup(struct inode *dir, struct dentry *dentry) static int ramfs_readpage(struct file *file, struct page * page) { if (!Page_Uptodate(page)) { - memset((void *) kmap(page), 0, PAGE_CACHE_SIZE); - kunmap(page); + memset((void *) page_address(page), 0, PAGE_CACHE_SIZE); SetPageUptodate(page); } UnlockPage(page); @@ -88,6 +86,7 @@ static int ramfs_prepare_write(struct file *file, struct page *page, unsigned of { void *addr; + addr = (void *) kmap(page); if (!Page_Uptodate(page)) { memset(addr, 0, PAGE_CACHE_SIZE); SetPageUptodate(page); diff --git a/fs/readdir.c b/fs/readdir.c index 059ab391d..8f40d846a 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -90,6 +90,8 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) +#ifndef __ia64__ + struct old_linux_dirent { unsigned long d_ino; unsigned long d_offset; @@ -144,6 +146,8 @@ out: return error; } +#endif /* !__ia64__ */ + /* * New, all-improved, singing, dancing, iBCS2-compliant getdents() * interface. diff --git a/fs/select.c b/fs/select.c index 3ee120746..86c2793d7 100644 --- a/fs/select.c +++ b/fs/select.c @@ -18,7 +18,6 @@ #include <linux/smp_lock.h> #include <linux/poll.h> #include <linux/file.h> -#include <linux/vmalloc.h> #include <asm/uaccess.h> @@ -53,7 +52,6 @@ static poll_table* alloc_wait(int nfds) if(out==NULL) return NULL; out->nr = 0; - out->err = 0; out->entry = (struct poll_table_entry *)(out + 1); out->next = NULL; nfds -=__MAX_POLL_TABLE_ENTRIES; @@ -99,36 +97,19 @@ static void free_wait(poll_table * p) void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p) { - poll_table* walk = p; for (;;) { - if (walk->nr < __MAX_POLL_TABLE_ENTRIES) { + if (p->nr < __MAX_POLL_TABLE_ENTRIES) { struct poll_table_entry * entry; -ok_table: - entry = walk->entry + walk->nr; + entry = p->entry + p->nr; get_file(filp); entry->filp = filp; entry->wait_address = wait_address; init_waitqueue_entry(&entry->wait, current); add_wait_queue(wait_address,&entry->wait); - walk->nr++; + p->nr++; return; } - if (walk->next == NULL) { - poll_table *tmp; - current->state=TASK_RUNNING; - tmp = (poll_table *) __get_free_page(GFP_KERNEL); - if (!tmp) { - p->err=-ENOMEM; - return; - } - tmp->nr = 0; - tmp->entry = (struct poll_table_entry *)(tmp + 1); - tmp->next = NULL; - walk->next = tmp; - walk = tmp; - goto ok_table; - } - walk = walk->next; + p = p->next; } } @@ -245,16 +226,11 @@ int do_select(int n, fd_set_bits *fds, long *timeout) wait = NULL; } } + wait = NULL; if (retval || !__timeout || signal_pending(current)) break; - if(orig_wait->err) { - retval=orig_wait->err; - goto out; - } - wait = NULL; __timeout = schedule_timeout(__timeout); } -out: current->state = TASK_RUNNING; free_wait(orig_wait); @@ -318,10 +294,7 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) */ ret = -ENOMEM; size = FDS_BYTES(n); - if(size>8000) - bits = vmalloc(6 * size); - else - bits = kmalloc(6 * size, GFP_KERNEL); + bits = kmalloc(6 * size, GFP_KERNEL); if (!bits) goto out_nofds; fds.in = (unsigned long *) bits; @@ -366,10 +339,7 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) set_fd_set(n, exp, fds.res_ex); out: - if(size>8000) - vfree(bits); - else - kfree(bits); + kfree(bits); out_nofds: return ret; } @@ -412,7 +382,6 @@ static int do_poll(unsigned int nfds, unsigned int nchunks, unsigned int nleft, struct pollfd *fds[], poll_table *wait, long timeout) { int count = 0; - poll_table* orig_wait = wait; for (;;) { unsigned int i; @@ -422,16 +391,11 @@ static int do_poll(unsigned int nfds, unsigned int nchunks, unsigned int nleft, do_pollfd(POLLFD_PER_PAGE, fds[i], &wait, &count); if (nleft) do_pollfd(nleft, fds[nchunks], &wait, &count); + wait = NULL; if (count || !timeout || signal_pending(current)) break; - if(orig_wait->err) { - count=orig_wait->err; - goto out; - } - wait=NULL; timeout = schedule_timeout(timeout); } -out: current->state = TASK_RUNNING; return count; } diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 49d47afa7..b47e236b0 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -27,7 +27,7 @@ /* #define pr_debug printk */ static int -smb_fsync(struct file *file, struct dentry * dentry, int datasync) +smb_fsync(struct file *file, struct dentry * dentry) { #ifdef SMBFS_DEBUG_VERBOSE printk("smb_fsync: sync file %s/%s\n", diff --git a/fs/super.c b/fs/super.c index 57d3698d3..5b8974e5b 100644 --- a/fs/super.c +++ b/fs/super.c @@ -281,28 +281,14 @@ static struct file_system_type *get_fs_type(const char *name) 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 - * - * This is VFS idea of mount. New node is allocated, bound to a tree - * we are mounting and optionally (OK, usually) registered as mounted - * on a given mountpoint. Returns a pointer to new node or %NULL in - * case of failure. - * - * Potential reason for failure (aside of trivial lack of memory) is a - * deleted mountpoint. Caller must hold ->i_zombie on mountpoint - * dentry (if any). - */ - -static struct vfsmount *add_vfsmnt(struct nameidata *nd, +static struct vfsmount *add_vfsmnt(struct super_block *sb, + struct dentry *mountpoint, struct dentry *root, - const char *dev_name) + struct vfsmount *parent, + const char *dev_name, + const char *dir_name) { struct vfsmount *mnt; - struct super_block *sb = root->d_inode->i_sb; char *name; mnt = kmalloc(sizeof(struct vfsmount), GFP_KERNEL); @@ -310,7 +296,13 @@ static struct vfsmount *add_vfsmnt(struct nameidata *nd, goto out; memset(mnt, 0, sizeof(struct vfsmount)); - /* It may be NULL, but who cares? */ + atomic_set(&mnt->mnt_count,1); + mnt->mnt_sb = sb; + mnt->mnt_mountpoint = dget(mountpoint); + mnt->mnt_root = dget(root); + mnt->mnt_parent = parent ? mntget(parent) : mnt; + + /* N.B. Is it really OK to have a vfsmount without names? */ if (dev_name) { name = kmalloc(strlen(dev_name)+1, GFP_KERNEL); if (name) { @@ -318,53 +310,51 @@ static struct vfsmount *add_vfsmnt(struct nameidata *nd, mnt->mnt_devname = name; } } + name = kmalloc(strlen(dir_name)+1, GFP_KERNEL); + if (name) { + strcpy(name, dir_name); + mnt->mnt_dirname = name; + } mnt->mnt_owner = current->uid; - atomic_set(&mnt->mnt_count,1); - mnt->mnt_sb = sb; - - if (nd && !IS_ROOT(nd->dentry) && d_unhashed(nd->dentry)) - goto fail; - mnt->mnt_root = dget(root); - mnt->mnt_mountpoint = nd ? dget(nd->dentry) : dget(root); - mnt->mnt_parent = nd ? mntget(nd->mnt) : mnt; - if (nd) { - list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts); - list_add(&mnt->mnt_clash, &nd->dentry->d_vfsmnt); - } else { + if (parent) + list_add(&mnt->mnt_child, &parent->mnt_mounts); + else INIT_LIST_HEAD(&mnt->mnt_child); - INIT_LIST_HEAD(&mnt->mnt_clash); - } INIT_LIST_HEAD(&mnt->mnt_mounts); list_add(&mnt->mnt_instances, &sb->s_mounts); + list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt); list_add(&mnt->mnt_list, vfsmntlist.prev); out: return mnt; -fail: - kfree(mnt->mnt_devname); - kfree(mnt); - return NULL; } static void move_vfsmnt(struct vfsmount *mnt, struct dentry *mountpoint, struct vfsmount *parent, - const char *dev_name) + const char *dev_name, + const char *dir_name) { - struct dentry *old_mountpoint; - struct vfsmount *old_parent; - char *new_devname = NULL; + struct dentry *old_mountpoint = mnt->mnt_mountpoint; + struct vfsmount *old_parent = mnt->mnt_parent; + char *new_devname = NULL, *new_dirname = NULL; if (dev_name) { new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL); if (new_devname) strcpy(new_devname, dev_name); } - - old_mountpoint = mnt->mnt_mountpoint; - old_parent = mnt->mnt_parent; + if (dir_name) { + new_dirname = kmalloc(strlen(dir_name)+1, GFP_KERNEL); + if (new_dirname) + strcpy(new_dirname, dir_name); + } /* flip names */ + if (new_dirname) { + kfree(mnt->mnt_dirname); + mnt->mnt_dirname = new_dirname; + } if (new_devname) { kfree(mnt->mnt_devname); mnt->mnt_devname = new_devname; @@ -375,13 +365,11 @@ static void move_vfsmnt(struct vfsmount *mnt, mnt->mnt_parent = parent ? mntget(parent) : mnt; list_del(&mnt->mnt_clash); list_del(&mnt->mnt_child); - if (parent) { + list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt); + if (parent) list_add(&mnt->mnt_child, &parent->mnt_mounts); - list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt); - } else { + else INIT_LIST_HEAD(&mnt->mnt_child); - INIT_LIST_HEAD(&mnt->mnt_clash); - } /* put the old stuff */ dput(old_mountpoint); @@ -403,6 +391,7 @@ static void remove_vfsmnt(struct vfsmount *mnt) dput(mnt->mnt_mountpoint); dput(mnt->mnt_root); kfree(mnt->mnt_devname); + kfree(mnt->mnt_dirname); kfree(mnt); } @@ -749,6 +738,10 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type, /* Done with lookups, semaphore down */ down(&mount_sem); dev = to_kdev_t(bdev->bd_dev); + check_disk_change(dev); + error = -EACCES; + if (!(flags & MS_RDONLY) && is_read_only(dev)) + goto out; sb = get_super(dev); if (sb) { if (fs_type == sb->s_type) { @@ -762,10 +755,6 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type, error = blkdev_get(bdev, mode, 0, BDEV_FS); if (error) goto out; - check_disk_change(dev); - error = -EACCES; - if (!(flags & MS_RDONLY) && is_read_only(dev)) - goto out1; error = -EINVAL; sb = read_super(dev, bdev, fs_type, flags, data, 0); if (sb) { @@ -773,7 +762,6 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type, path_release(&nd); return sb; } -out1: blkdev_put(bdev, BDEV_FS); } out: @@ -907,7 +895,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(sb, sb->s_root, sb->s_root, NULL, "none", type->name); if (!mnt) { kill_super(sb, 0); return ERR_PTR(-ENOMEM); @@ -921,7 +909,10 @@ struct vfsmount *kern_mount(struct file_system_type *type) void kern_umount(struct vfsmount *mnt) { struct super_block *sb = mnt->mnt_sb; + struct dentry *root = sb->s_root; remove_vfsmnt(mnt); + dput(root); + sb->s_root = NULL; kill_super(sb, 0); } @@ -941,16 +932,6 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags) { struct super_block * sb = mnt->mnt_sb; - /* - * No sense to grab the lock for this test, but test itself looks - * somewhat bogus. Suggestions for better replacement? - * Ho-hum... In principle, we might treat that as umount + switch - * to rootfs. GC would eventually take care of the old vfsmount. - * The problem being: we have to implement rootfs and GC for that ;-) - * Actually it makes sense, especially if rootfs would contain a - * /reboot - static binary that would close all descriptors and - * call reboot(9). Then init(8) could umount root and exec /reboot. - */ if (mnt == current->fs->rootmnt && !umount_root) { int retval = 0; /* @@ -971,7 +952,6 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags) if (mnt->mnt_instances.next != mnt->mnt_instances.prev) { if (sb->s_type->fs_flags & FS_SINGLE) put_filesystem(sb->s_type); - /* We hold two references, so mntput() is safe */ mntput(mnt); remove_vfsmnt(mnt); return 0; @@ -1008,14 +988,14 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags) shrink_dcache_sb(sb); fsync_dev(sb->s_dev); - if (sb->s_root->d_inode->i_state) { + /* Something might grab it again - redo checks */ + + if (atomic_read(&mnt->mnt_count) > 2) { mntput(mnt); return -EBUSY; } - /* Something might grab it again - redo checks */ - - if (atomic_read(&mnt->mnt_count) > 2) { + if (sb->s_root->d_inode->i_state) { mntput(mnt); return -EBUSY; } @@ -1087,8 +1067,6 @@ static int mount_is_safe(struct nameidata *nd) { if (capable(CAP_SYS_ADMIN)) return 0; - return -EPERM; -#ifdef notyet if (S_ISLNK(nd->dentry->d_inode->i_mode)) return -EPERM; if (nd->dentry->d_inode->i_mode & S_ISVTX) { @@ -1098,7 +1076,6 @@ static int mount_is_safe(struct nameidata *nd) if (permission(nd->dentry->d_inode, MAY_WRITE)) return -EPERM; return 0; -#endif } /* @@ -1125,22 +1102,22 @@ static int do_loopback(char *old_name, char *new_name) if (S_ISDIR(new_nd.dentry->d_inode->i_mode) != S_ISDIR(old_nd.dentry->d_inode->i_mode)) goto out2; - - err = -ENOMEM; - if (old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE) - get_filesystem(old_nd.mnt->mnt_sb->s_type); down(&mount_sem); + err = -ENOENT; + if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry)) + goto out3; + if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry)) + goto out3; /* there we go */ - down(&new_nd.dentry->d_inode->i_zombie); - if (IS_DEADDIR(new_nd.dentry->d_inode)) - err = -ENOENT; - else if (add_vfsmnt(&new_nd, old_nd.dentry, old_nd.mnt->mnt_devname)) + err = -ENOMEM; + if (old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE) + get_filesystem(old_nd.mnt->mnt_sb->s_type); + if (add_vfsmnt(old_nd.mnt->mnt_sb, new_nd.dentry, old_nd.dentry, + new_nd.mnt, old_nd.mnt->mnt_devname, new_name)) err = 0; - up(&new_nd.dentry->d_inode->i_zombie); +out3: up(&mount_sem); - if (err && old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE) - put_filesystem(old_nd.mnt->mnt_sb->s_type); out2: path_release(&new_nd); out1: @@ -1238,7 +1215,7 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, { struct file_system_type * fstype; struct nameidata nd; - struct vfsmount *mnt = NULL; + struct vfsmount *mnt; struct super_block *sb; int retval = 0; unsigned long flags = 0; @@ -1247,6 +1224,8 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) return -EINVAL; + if (!type_page || !memchr(type_page, 0, PAGE_SIZE)) + return -EINVAL; if (dev_name && !memchr(dev_name, 0, PAGE_SIZE)) return -EINVAL; @@ -1260,11 +1239,6 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) flags = new_flags & ~MS_MGC_MSK; - /* For the rest we need the type */ - - if (!type_page || !memchr(type_page, 0, PAGE_SIZE)) - return -EINVAL; - /* loopback mount? This is special - requires fewer capabilities */ if (strcmp(type_page, "bind")==0) return do_loopback(dev_name, dir_name); @@ -1298,18 +1272,16 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, if (IS_ERR(sb)) goto dput_out; + retval = -ENOENT; + if (d_unhashed(nd.dentry) && !IS_ROOT(nd.dentry)) + goto fail; + /* Something was mounted here while we slept */ while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry)) ; - retval = -ENOENT; - if (!nd.dentry->d_inode) - goto fail; - down(&nd.dentry->d_inode->i_zombie); - if (!IS_DEADDIR(nd.dentry->d_inode)) { - retval = -ENOMEM; - mnt = add_vfsmnt(&nd, sb->s_root, dev_name); - } - up(&nd.dentry->d_inode->i_zombie); + + retval = -ENOMEM; + mnt = add_vfsmnt(sb, nd.dentry, sb->s_root, nd.mnt, dev_name, dir_name); if (!mnt) goto fail; retval = 0; @@ -1340,6 +1312,15 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, if (retval < 0) return retval; + /* copy_mount_options allows a NULL user pointer, + * and just returns zero in that case. But if we + * allow the type to be NULL we will crash. + * Previously we did not check this case. + */ + if (type_page == 0) + return -EINVAL; + + lock_kernel(); dir_page = getname(dir_name); retval = PTR_ERR(dir_page); if (IS_ERR(dir_page)) @@ -1350,10 +1331,8 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, goto out2; retval = copy_mount_options (data, &data_page); if (retval >= 0) { - lock_kernel(); retval = do_mount((char*)dev_page,dir_page,(char*)type_page, new_flags, (void*)data_page); - unlock_kernel(); free_page(data_page); } free_page(dev_page); @@ -1361,6 +1340,7 @@ out2: putname(dir_page); out1: free_page(type_page); + unlock_kernel(); return retval; } @@ -1510,11 +1490,12 @@ mount_it: path + 5 + path_start, 0, NULL, NULL); memcpy (path + path_start, "/dev/", 5); - vfsmnt = add_vfsmnt(NULL, sb->s_root, path + path_start); + vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL, + path + path_start, "/"); } else - vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root"); - /* FIXME: if something will try to umount us right now... */ + vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL, + "/dev/root", "/"); if (vfsmnt) { set_fs_root(current->fs, vfsmnt, sb->s_root); set_fs_pwd(current->fs, vfsmnt, sb->s_root); @@ -1535,7 +1516,6 @@ static void chroot_fs_refs(struct dentry *old_root, read_lock(&tasklist_lock); for_each_task(p) { - /* FIXME - unprotected usage of ->fs + (harmless) race */ if (!p->fs) continue; if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) set_fs_root(p->fs, new_rootmnt, new_root); @@ -1596,10 +1576,7 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) root_mnt = mntget(current->fs->rootmnt); root = dget(current->fs->root); down(&mount_sem); - down(&old_nd.dentry->d_inode->i_zombie); error = -ENOENT; - if (IS_DEADDIR(new_nd.dentry->d_inode)) - goto out2; if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry)) goto out2; if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry)) @@ -1622,12 +1599,19 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) } else if (!is_subdir(old_nd.dentry, new_nd.dentry)) goto out2; - move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL); - move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL); + error = -ENOMEM; + name = __getname(); + if (!name) + goto out2; + + move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL, "/"); + move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL, + __d_path(old_nd.dentry, old_nd.mnt, new_nd.dentry, + new_nd.mnt, name, PAGE_SIZE)); + putname(name); chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt); error = 0; out2: - up(&old_nd.dentry->d_inode->i_zombie); up(&mount_sem); dput(root); mntput(root_mnt); @@ -1645,11 +1629,10 @@ out0: int __init change_root(kdev_t new_root_dev,const char *put_old) { kdev_t old_root_dev = ROOT_DEV; - struct vfsmount *old_rootmnt; + struct vfsmount *old_rootmnt = mntget(current->fs->rootmnt); struct nameidata devfs_nd, nd; int error = 0; - old_rootmnt = mntget(current->fs->rootmnt); /* First unmount devfs if mounted */ if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd)) error = path_walk("/dev", &devfs_nd); @@ -1692,8 +1675,7 @@ int __init change_root(kdev_t new_root_dev,const char *put_old) printk(KERN_ERR "error %ld\n",blivet); return error; } - /* FIXME: we should hold i_zombie on nd.dentry */ - move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old"); + move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old", put_old); mntput(old_rootmnt); path_release(&nd); return 0; diff --git a/fs/sysv/fsync.c b/fs/sysv/fsync.c index 091605cd1..3c9871be6 100644 --- a/fs/sysv/fsync.c +++ b/fs/sysv/fsync.c @@ -178,7 +178,7 @@ static int sync_tindirect(struct inode *inode, u32 *tiblockp, int convert, return err; } -int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync) +int sysv_sync_file(struct file * file, struct dentry *dentry) { int wait, err = 0; struct inode *inode = dentry->d_inode; diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c index bbd88336c..d7cc12187 100644 --- a/fs/sysv/ialloc.c +++ b/fs/sysv/ialloc.c @@ -142,7 +142,7 @@ struct inode * sysv_new_inode(const struct inode * dir) /* Change directory entry: */ inode->i_mode = 0; /* for sysv_write_inode() */ inode->i_size = 0; /* ditto */ - sysv_write_inode(inode, 0); /* ensure inode not allocated again */ + sysv_write_inode(inode); /* ensure inode not allocated again */ /* FIXME: caller may call this too. */ mark_inode_dirty(inode); /* cleared by sysv_write_inode() */ /* That's it. */ diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 9f8df88e4..455818959 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -496,6 +496,7 @@ static struct super_block *sysv_read_super(struct super_block *sb, sb->s_blocksize = sb->sv_block_size; sb->s_blocksize_bits = sb->sv_block_size_bits; /* set up enough so that it can read an inode */ + sb->s_dev = dev; sb->s_op = &sysv_sops; root_inode = iget(sb,SYSV_ROOT_INO); sb->s_root = d_alloc_root(root_inode); @@ -1153,7 +1154,7 @@ static struct buffer_head * sysv_update_inode(struct inode * inode) return bh; } -void sysv_write_inode(struct inode * inode, int unused) +void sysv_write_inode(struct inode * inode) { struct buffer_head *bh; bh = sysv_update_inode(inode); diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c index 64a5e41a1..e7d067e62 100644 --- a/fs/udf/fsync.c +++ b/fs/udf/fsync.c @@ -96,7 +96,7 @@ static int sync_all_extents(struct inode * inode, int wait) * even pass file to fsync ? */ -int udf_sync_file(struct file * file, struct dentry *dentry, int dsync) +int udf_sync_file(struct file * file, struct dentry *dentry) { int wait, err = 0; struct inode *inode = dentry->d_inode; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 3c2d50340..8c38883c0 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1213,10 +1213,10 @@ udf_convert_permissions(struct FileEntry *fe) * Written, tested, and released. */ -void udf_write_inode(struct inode * inode, int wait) +void udf_write_inode(struct inode * inode) { lock_kernel(); - udf_update_inode(inode, wait); + udf_update_inode(inode, 0); unlock_kernel(); } diff --git a/fs/udf/super.c b/fs/udf/super.c index f3f575d7e..5f76abbb0 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1419,6 +1419,7 @@ udf_read_super(struct super_block *sb, void *options, int silent) return sb; error_out: + sb->s_dev = NODEV; if (UDF_SB_VAT(sb)) iput(UDF_SB_VAT(sb)); if (!(sb->s_flags & MS_RDONLY)) diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 115db1bef..7dd00bc19 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -134,7 +134,7 @@ extern struct buffer_head * udf_bread(struct inode *, int, int, int *); extern void udf_read_inode(struct inode *); extern void udf_put_inode(struct inode *); extern void udf_delete_inode(struct inode *); -extern void udf_write_inode(struct inode *, int); +extern void udf_write_inode(struct inode *); extern long udf_locked_block_map(struct inode *, long); extern long udf_block_map(struct inode *, long); extern int inode_bmap(struct inode *, int, lb_addr *, Uint32 *, lb_addr *, Uint32 *, Uint32 *, struct buffer_head **); @@ -184,7 +184,7 @@ extern int udf_prealloc_blocks(const struct inode *, Uint16, Uint32, Uint32); extern int udf_new_block(const struct inode *, Uint16, Uint32, int *); /* fsync.c */ -extern int udf_sync_file(struct file *, struct dentry *, int data); +extern int udf_sync_file(struct file *, struct dentry *); /* directory.c */ extern Uint8 * udf_filead_read(struct inode *, Uint8 *, Uint8, lb_addr, int *, int *, struct buffer_head **, int *); diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 2a1d0f6ae..7801add9a 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -744,7 +744,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync) return 0; } -void ufs_write_inode (struct inode * inode, int unused) +void ufs_write_inode (struct inode * inode) { ufs_update_inode (inode, 0); } diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index e4c991dc0..14b23467d 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -29,7 +29,7 @@ static struct dentry *check_pseudo_root(struct super_block *); /* - * Initialize a private filp. dentry is always a regular file one. + * Initialize a private filp */ void fill_new_filp (struct file *filp, struct dentry *dentry) { @@ -293,11 +293,11 @@ out: /* * Update the disk with the inode content */ -void UMSDOS_write_inode (struct inode *inode, int unused) +void UMSDOS_write_inode (struct inode *inode) { struct iattr newattrs; - fat_write_inode (inode, 0); + fat_write_inode (inode); newattrs.ia_mtime = inode->i_mtime; newattrs.ia_atime = inode->i_atime; newattrs.ia_ctime = inode->i_ctime; |