diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/aio.c | 1 | ||||
-rw-r--r-- | fs/compat.c | 4 | ||||
-rw-r--r-- | fs/dcache.c | 3 | ||||
-rw-r--r-- | fs/eventpoll.c | 40 | ||||
-rw-r--r-- | fs/exec.c | 10 | ||||
-rw-r--r-- | fs/fat/file.c | 37 | ||||
-rw-r--r-- | fs/fat/inode.c | 15 | ||||
-rw-r--r-- | fs/file.c | 10 | ||||
-rw-r--r-- | fs/locks.c | 3 | ||||
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 24 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 90 | ||||
-rw-r--r-- | fs/ntfs/ChangeLog | 2 | ||||
-rw-r--r-- | fs/ntfs/aops.c | 122 | ||||
-rw-r--r-- | fs/ntfs/inode.c | 9 | ||||
-rw-r--r-- | fs/ntfs/malloc.h | 2 | ||||
-rw-r--r-- | fs/ntfs/runlist.c | 132 | ||||
-rw-r--r-- | fs/open.c | 98 | ||||
-rw-r--r-- | fs/proc/array.c | 3 | ||||
-rw-r--r-- | fs/reiserfs/file.c | 11 | ||||
-rw-r--r-- | fs/reiserfs/inode.c | 16 |
21 files changed, 339 insertions, 295 deletions
@@ -562,6 +562,7 @@ static inline void lock_kiocb(struct kiocb *iocb) static inline void unlock_kiocb(struct kiocb *iocb) { kiocbClearLocked(iocb); + smp_mb__after_clear_bit(); wake_up_bit(&iocb->ki_flags, KIF_LOCKED); } diff --git a/fs/compat.c b/fs/compat.c index ac3fb9ed8ee..a719e158e00 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -44,6 +44,8 @@ #include <linux/nfsd/syscall.h> #include <linux/personality.h> #include <linux/rwsem.h> +#include <linux/acct.h> +#include <linux/mm.h> #include <net/sock.h> /* siocdevprivate_ioctl */ @@ -1487,6 +1489,8 @@ int compat_do_execve(char * filename, /* execve success */ security_bprm_free(bprm); + acct_update_integrals(current); + update_mem_hiwater(current); kfree(bprm); return retval; } diff --git a/fs/dcache.c b/fs/dcache.c index 7376b61269f..fb10386c59b 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -102,7 +102,8 @@ static inline void dentry_iput(struct dentry * dentry) list_del_init(&dentry->d_alias); spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); - fsnotify_inoderemove(inode); + if (!inode->i_nlink) + fsnotify_inoderemove(inode); if (dentry->d_op && dentry->d_op->d_iput) dentry->d_op->d_iput(dentry, inode); else diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 6ab1dd0ca90..403b90a1213 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -231,8 +231,9 @@ struct ep_pqueue { static void ep_poll_safewake_init(struct poll_safewake *psw); static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq); -static int ep_getfd(int *efd, struct inode **einode, struct file **efile); -static int ep_file_init(struct file *file); +static int ep_getfd(int *efd, struct inode **einode, struct file **efile, + struct eventpoll *ep); +static int ep_alloc(struct eventpoll **pep); static void ep_free(struct eventpoll *ep); static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd); static void ep_use_epitem(struct epitem *epi); @@ -501,38 +502,37 @@ void eventpoll_release_file(struct file *file) asmlinkage long sys_epoll_create(int size) { int error, fd; + struct eventpoll *ep; struct inode *inode; struct file *file; DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", current, size)); - /* Sanity check on the size parameter */ + /* + * Sanity check on the size parameter, and create the internal data + * structure ( "struct eventpoll" ). + */ error = -EINVAL; - if (size <= 0) + if (size <= 0 || (error = ep_alloc(&ep)) != 0) goto eexit_1; /* * Creates all the items needed to setup an eventpoll file. That is, * a file structure, and inode and a free file descriptor. */ - error = ep_getfd(&fd, &inode, &file); - if (error) - goto eexit_1; - - /* Setup the file internal data structure ( "struct eventpoll" ) */ - error = ep_file_init(file); + error = ep_getfd(&fd, &inode, &file, ep); if (error) goto eexit_2; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", current, size, fd)); return fd; eexit_2: - sys_close(fd); + ep_free(ep); + kfree(ep); eexit_1: DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", current, size, error)); @@ -706,7 +706,8 @@ eexit_1: /* * Creates the file descriptor to be used by the epoll interface. */ -static int ep_getfd(int *efd, struct inode **einode, struct file **efile) +static int ep_getfd(int *efd, struct inode **einode, struct file **efile, + struct eventpoll *ep) { struct qstr this; char name[32]; @@ -756,7 +757,7 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile) file->f_op = &eventpoll_fops; file->f_mode = FMODE_READ; file->f_version = 0; - file->private_data = NULL; + file->private_data = ep; /* Install the new setup file into the allocated fd. */ fd_install(fd, file); @@ -777,14 +778,13 @@ eexit_1: } -static int ep_file_init(struct file *file) +static int ep_alloc(struct eventpoll **pep) { - struct eventpoll *ep; + struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL); - if (!(ep = kmalloc(sizeof(struct eventpoll), GFP_KERNEL))) + if (!ep) return -ENOMEM; - memset(ep, 0, sizeof(*ep)); rwlock_init(&ep->lock); init_rwsem(&ep->sem); init_waitqueue_head(&ep->wq); @@ -792,9 +792,9 @@ static int ep_file_init(struct file *file) INIT_LIST_HEAD(&ep->rdllist); ep->rbr = RB_ROOT; - file->private_data = ep; + *pep = ep; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_file_init() ep=%p\n", + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n", current, ep)); return 0; } diff --git a/fs/exec.c b/fs/exec.c index 14dd03907cc..a04a575ad43 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -421,11 +421,6 @@ int setup_arg_pages(struct linux_binprm *bprm, if (!mpnt) return -ENOMEM; - if (security_vm_enough_memory(arg_size >> PAGE_SHIFT)) { - kmem_cache_free(vm_area_cachep, mpnt); - return -ENOMEM; - } - memset(mpnt, 0, sizeof(*mpnt)); down_write(&mm->mmap_sem); @@ -745,8 +740,8 @@ static inline int de_thread(struct task_struct *tsk) } /* - * Now there are really no other threads at all, - * so it's safe to stop telling them to kill themselves. + * There may be one thread left which is just exiting, + * but it's safe to stop telling the group to kill themselves. */ sig->flags = 0; @@ -785,7 +780,6 @@ no_thread_group: kmem_cache_free(sighand_cachep, oldsighand); } - BUG_ON(!thread_group_empty(current)); BUG_ON(!thread_group_leader(current)); return 0; } diff --git a/fs/fat/file.c b/fs/fat/file.c index 62ffa913940..7134403d5be 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -12,39 +12,6 @@ #include <linux/smp_lock.h> #include <linux/buffer_head.h> -static ssize_t fat_file_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) -{ - struct inode *inode = iocb->ki_filp->f_dentry->d_inode; - int retval; - - retval = generic_file_aio_write(iocb, buf, count, pos); - if (retval > 0) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - MSDOS_I(inode)->i_attrs |= ATTR_ARCH; - mark_inode_dirty(inode); -// check the locking rules -// if (IS_SYNC(inode)) -// fat_sync_inode(inode); - } - return retval; -} - -static ssize_t fat_file_writev(struct file *filp, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct inode *inode = filp->f_dentry->d_inode; - int retval; - - retval = generic_file_writev(filp, iov, nr_segs, ppos); - if (retval > 0) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - MSDOS_I(inode)->i_attrs |= ATTR_ARCH; - mark_inode_dirty(inode); - } - return retval; -} - int fat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -148,9 +115,9 @@ struct file_operations fat_file_operations = { .read = do_sync_read, .write = do_sync_write, .readv = generic_file_readv, - .writev = fat_file_writev, + .writev = generic_file_writev, .aio_read = generic_file_aio_read, - .aio_write = fat_file_aio_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .ioctl = fat_generic_ioctl, .fsync = file_fsync, diff --git a/fs/fat/inode.c b/fs/fat/inode.c index a7cbe68e225..51b1d15d9d5 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -102,6 +102,19 @@ static int fat_prepare_write(struct file *file, struct page *page, &MSDOS_I(page->mapping->host)->mmu_private); } +static int fat_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + int err = generic_commit_write(file, page, from, to); + if (!err && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + MSDOS_I(inode)->i_attrs |= ATTR_ARCH; + mark_inode_dirty(inode); + } + return err; +} + static sector_t _fat_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping, block, fat_get_block); @@ -112,7 +125,7 @@ static struct address_space_operations fat_aops = { .writepage = fat_writepage, .sync_page = block_sync_page, .prepare_write = fat_prepare_write, - .commit_write = generic_commit_write, + .commit_write = fat_commit_write, .bmap = _fat_bmap }; diff --git a/fs/file.c b/fs/file.c index 2127a7b9dc3..fd066b261c7 100644 --- a/fs/file.c +++ b/fs/file.c @@ -69,13 +69,9 @@ void free_fd_array(struct file **array, int num) static void __free_fdtable(struct fdtable *fdt) { - int fdset_size, fdarray_size; - - fdset_size = fdt->max_fdset / 8; - fdarray_size = fdt->max_fds * sizeof(struct file *); - free_fdset(fdt->open_fds, fdset_size); - free_fdset(fdt->close_on_exec, fdset_size); - free_fd_array(fdt->fd, fdarray_size); + free_fdset(fdt->open_fds, fdt->max_fdset); + free_fdset(fdt->close_on_exec, fdt->max_fdset); + free_fd_array(fdt->fd, fdt->max_fds); kfree(fdt); } diff --git a/fs/locks.c b/fs/locks.c index c2c09b4798d..f7daa5f4894 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -124,6 +124,7 @@ #include <linux/smp_lock.h> #include <linux/syscalls.h> #include <linux/time.h> +#include <linux/rcupdate.h> #include <asm/semaphore.h> #include <asm/uaccess.h> @@ -2205,6 +2206,7 @@ void steal_locks(fl_owner_t from) lock_kernel(); j = 0; + rcu_read_lock(); fdt = files_fdtable(files); for (;;) { unsigned long set; @@ -2222,6 +2224,7 @@ void steal_locks(fl_owner_t from) set >>= 1; } } + rcu_read_unlock(); unlock_kernel(); } EXPORT_SYMBOL(steal_locks); diff --git a/fs/namei.c b/fs/namei.c index 21d85f1ac83..043d587216b 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1048,7 +1048,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata out: if (unlikely(current->audit_context && nd && nd->dentry && nd->dentry->d_inode)) - audit_inode(name, nd->dentry->d_inode); + audit_inode(name, nd->dentry->d_inode, flags); return retval; } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index e08edc17c6a..361b4007d4a 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -162,7 +162,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ static inline int -nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) +nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) { int status; dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", @@ -238,8 +238,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open */ status = nfsd4_process_open2(rqstp, current_fh, open); out: - if (open->op_stateowner) + if (open->op_stateowner) { nfs4_get_stateowner(open->op_stateowner); + *replay_owner = open->op_stateowner; + } nfs4_unlock_state(); return status; } @@ -809,8 +811,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfsd4_access(rqstp, current_fh, &op->u.access); break; case OP_CLOSE: - op->status = nfsd4_close(rqstp, current_fh, &op->u.close); - replay_owner = op->u.close.cl_stateowner; + op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner); break; case OP_COMMIT: op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit); @@ -831,15 +832,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); break; case OP_LOCK: - op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock); - replay_owner = op->u.lock.lk_stateowner; + op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner); break; case OP_LOCKT: op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt); break; case OP_LOCKU: - op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku); - replay_owner = op->u.locku.lu_stateowner; + op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner); break; case OP_LOOKUP: op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup); @@ -853,16 +852,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfs_ok; break; case OP_OPEN: - op->status = nfsd4_open(rqstp, current_fh, &op->u.open); - replay_owner = op->u.open.op_stateowner; + op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner); break; case OP_OPEN_CONFIRM: - op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm); - replay_owner = op->u.open_confirm.oc_stateowner; + op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner); break; case OP_OPEN_DOWNGRADE: - op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade); - replay_owner = op->u.open_downgrade.od_stateowner; + op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner); break; case OP_PUTFH: op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b83f8fb441e..6bbefd06f10 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -624,7 +624,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) cb->cb_ident = se->se_callback_ident; return; out_err: - printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " + dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " "will not receive delegations\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); @@ -678,13 +678,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) int status; char dname[HEXDIR_LEN]; - status = nfserr_inval; if (!check_name(clname)) - goto out; + return nfserr_inval; status = nfs4_make_rec_clidname(dname, &clname); if (status) - goto out; + return status; /* * XXX The Duplicate Request Cache (DRC) has been checked (??) @@ -2014,7 +2013,7 @@ STALE_STATEID(stateid_t *stateid) { if (stateid->si_boot == boot_time) return 0; - printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", + dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); return 1; @@ -2275,7 +2274,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei check_replay: if (seqid == sop->so_seqid - 1) { - printk("NFSD: preprocess_seqid_op: retransmission?\n"); + dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); /* indicate replay to calling function */ return NFSERR_REPLAY_ME; } @@ -2286,7 +2285,7 @@ check_replay: } int -nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc) +nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateowner *sop; @@ -2320,8 +2319,10 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs nfsd4_create_clid_dir(sop->so_client); out: - if (oc->oc_stateowner) + if (oc->oc_stateowner) { nfs4_get_stateowner(oc->oc_stateowner); + *replay_owner = oc->oc_stateowner; + } nfs4_unlock_state(); return status; } @@ -2352,7 +2353,7 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) } int -nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od) +nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateid *stp; @@ -2394,8 +2395,10 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); status = nfs_ok; out: - if (od->od_stateowner) + if (od->od_stateowner) { nfs4_get_stateowner(od->od_stateowner); + *replay_owner = od->od_stateowner; + } nfs4_unlock_state(); return status; } @@ -2404,7 +2407,7 @@ out: * nfs4_unlock_state() called after encode */ int -nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close) +nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateid *stp; @@ -2430,8 +2433,10 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos /* release_state_owner() calls nfsd_close() if needed */ release_state_owner(stp, OPEN_STATE); out: - if (close->cl_stateowner) + if (close->cl_stateowner) { nfs4_get_stateowner(close->cl_stateowner); + *replay_owner = close->cl_stateowner; + } nfs4_unlock_state(); return status; } @@ -2500,8 +2505,7 @@ find_stateid(stateid_t *stid, int flags) (local->st_stateid.si_fileid == f_id)) return local; } - } else - printk("NFSD: find_stateid: ERROR: no state flag\n"); + } return NULL; } @@ -2624,7 +2628,9 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str sop->so_is_open_owner = 0; sop->so_id = current_ownerid++; sop->so_client = clp; - sop->so_seqid = lock->lk_new_lock_seqid; + /* It is the openowner seqid that will be incremented in encode in the + * case of new lockowners; so increment the lock seqid manually: */ + sop->so_seqid = lock->lk_new_lock_seqid + 1; sop->so_confirmed = 1; rp = &sop->so_replay; rp->rp_status = NFSERR_SERVERFAULT; @@ -2676,9 +2682,10 @@ check_lock_length(u64 offset, u64 length) * LOCK operation */ int -nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) +nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner) { struct nfs4_stateowner *open_sop = NULL; + struct nfs4_stateowner *lock_sop = NULL; struct nfs4_stateid *lock_stp; struct file *filp; struct file_lock file_lock; @@ -2705,19 +2712,19 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock struct nfs4_file *fp; status = nfserr_stale_clientid; - if (STALE_CLIENTID(&lock->lk_new_clientid)) { - printk("NFSD: nfsd4_lock: clientid is stale!\n"); + if (STALE_CLIENTID(&lock->lk_new_clientid)) goto out; - } /* validate and update open stateid and open seqid */ status = nfs4_preprocess_seqid_op(current_fh, lock->lk_new_open_seqid, &lock->lk_new_open_stateid, CHECK_FH | OPEN_STATE, - &open_sop, &open_stp, lock); + &lock->lk_stateowner, &open_stp, + lock); if (status) goto out; + open_sop = lock->lk_stateowner; /* create lockowner and lock stateid */ fp = open_stp->st_file; strhashval = lock_ownerstr_hashval(fp->fi_inode, @@ -2727,16 +2734,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock * the same file, or should they just be allowed (and * create new stateids)? */ status = nfserr_resource; - if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) + lock_sop = alloc_init_lock_stateowner(strhashval, + open_sop->so_client, open_stp, lock); + if (lock_sop == NULL) goto out; - if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, - fp, open_stp)) == NULL) { - release_stateowner(lock->lk_stateowner); - lock->lk_stateowner = NULL; + lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); + if (lock_stp == NULL) { + release_stateowner(lock_sop); goto out; } - /* bump the open seqid used to create the lock */ - open_sop->so_seqid++; } else { /* lock (lock owner + lock stateid) already exists */ status = nfs4_preprocess_seqid_op(current_fh, @@ -2746,12 +2752,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock &lock->lk_stateowner, &lock_stp, lock); if (status) goto out; + lock_sop = lock->lk_stateowner; } /* lock->lk_stateowner and lock_stp have been created or found */ filp = lock_stp->st_vfs_file; if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { - printk("NFSD: nfsd4_lock: permission denied!\n"); + dprintk("NFSD: nfsd4_lock: permission denied!\n"); goto out; } @@ -2776,7 +2783,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock status = nfserr_inval; goto out; } - file_lock.fl_owner = (fl_owner_t) lock->lk_stateowner; + file_lock.fl_owner = (fl_owner_t)lock_sop; file_lock.fl_pid = current->tgid; file_lock.fl_file = filp; file_lock.fl_flags = FL_POSIX; @@ -2832,14 +2839,13 @@ out_destroy_new_stateid: * An error encountered after instantiation of the new * stateid has forced us to destroy it. */ - if (!seqid_mutating_err(status)) - open_sop->so_seqid--; - release_state_owner(lock_stp, LOCK_STATE); } out: - if (lock->lk_stateowner) + if (lock->lk_stateowner) { nfs4_get_stateowner(lock->lk_stateowner); + *replay_owner = lock->lk_stateowner; + } nfs4_unlock_state(); return status; } @@ -2866,13 +2872,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock nfs4_lock_state(); status = nfserr_stale_clientid; - if (STALE_CLIENTID(&lockt->lt_clientid)) { - printk("NFSD: nfsd4_lockt: clientid is stale!\n"); + if (STALE_CLIENTID(&lockt->lt_clientid)) goto out; - } if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) { - printk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); + dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); if (status == nfserr_symlink) status = nfserr_inval; goto out; @@ -2930,7 +2934,7 @@ out: } int -nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku) +nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner) { struct nfs4_stateid *stp; struct file *filp = NULL; @@ -2976,7 +2980,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) file_lock.fl_ops->fl_release_private(&file_lock); if (status) { - printk("NFSD: nfs4_locku: posix_lock_file failed!\n"); + dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); goto out_nfserr; } /* @@ -2986,8 +2990,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); out: - if (locku->lu_stateowner) + if (locku->lu_stateowner) { nfs4_get_stateowner(locku->lu_stateowner); + *replay_owner = locku->lu_stateowner; + } nfs4_unlock_state(); return status; @@ -3036,10 +3042,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * /* XXX check for lease expiration */ status = nfserr_stale_clientid; - if (STALE_CLIENTID(clid)) { - printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n"); + if (STALE_CLIENTID(clid)) return status; - } nfs4_lock_state(); diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 49eafbdb15c..c7e9237379c 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -92,6 +92,8 @@ ToDo/Notes: an octal number to conform to how chmod(1) works, too. Thanks to Giuseppe Bilotta and Horst von Brand for pointing out the errors of my ways. + - Fix various bugs in the runlist merging code. (Based on libntfs + changes by Richard Russon.) 2.1.23 - Implement extension of resident files and make writing safe as well as many bug fixes, cleanups, and enhancements... diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index b6cc8cf2462..5e80c07c6a4 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -59,39 +59,49 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) unsigned long flags; struct buffer_head *first, *tmp; struct page *page; + struct inode *vi; ntfs_inode *ni; int page_uptodate = 1; page = bh->b_page; - ni = NTFS_I(page->mapping->host); + vi = page->mapping->host; + ni = NTFS_I(vi); if (likely(uptodate)) { - s64 file_ofs, initialized_size; + loff_t i_size; + s64 file_ofs, init_size; set_buffer_uptodate(bh); file_ofs = ((s64)page->index << PAGE_CACHE_SHIFT) + bh_offset(bh); read_lock_irqsave(&ni->size_lock, flags); - initialized_size = ni->initialized_size; + init_size = ni->initialized_size; + i_size = i_size_read(vi); read_unlock_irqrestore(&ni->size_lock, flags); + if (unlikely(init_size > i_size)) { + /* Race with shrinking truncate. */ + init_size = i_size; + } /* Check for the current buffer head overflowing. */ - if (file_ofs + bh->b_size > initialized_size) { - char *addr; - int ofs = 0; - - if (file_ofs < initialized_size) - ofs = initialized_size - file_ofs; - addr = kmap_atomic(page, KM_BIO_SRC_IRQ); - memset(addr + bh_offset(bh) + ofs, 0, bh->b_size - ofs); + if (unlikely(file_ofs + bh->b_size > init_size)) { + u8 *kaddr; + int ofs; + + ofs = 0; + if (file_ofs < init_size) + ofs = init_size - file_ofs; + kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); + memset(kaddr + bh_offset(bh) + ofs, 0, + bh->b_size - ofs); + kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); flush_dcache_page(page); - kunmap_atomic(addr, KM_BIO_SRC_IRQ); } } else { clear_buffer_uptodate(bh); SetPageError(page); - ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %llu.", - (unsigned long long)bh->b_blocknr); + ntfs_error(ni->vol->sb, "Buffer I/O error, logical block " + "0x%llx.", (unsigned long long)bh->b_blocknr); } first = page_buffers(page); local_irq_save(flags); @@ -124,7 +134,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) if (likely(page_uptodate && !PageError(page))) SetPageUptodate(page); } else { - char *addr; + u8 *kaddr; unsigned int i, recs; u32 rec_size; @@ -132,12 +142,12 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) recs = PAGE_CACHE_SIZE / rec_size; /* Should have been verified before we got here... */ BUG_ON(!recs); - addr = kmap_atomic(page, KM_BIO_SRC_IRQ); + kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); for (i = 0; i < recs; i++) - post_read_mst_fixup((NTFS_RECORD*)(addr + + post_read_mst_fixup((NTFS_RECORD*)(kaddr + i * rec_size), rec_size); + kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); flush_dcache_page(page); - kunmap_atomic(addr, KM_BIO_SRC_IRQ); if (likely(page_uptodate && !PageError(page))) SetPageUptodate(page); } @@ -168,8 +178,11 @@ still_busy: */ static int ntfs_read_block(struct page *page) { + loff_t i_size; VCN vcn; LCN lcn; + s64 init_size; + struct inode *vi; ntfs_inode *ni; ntfs_volume *vol; runlist_element *rl; @@ -180,7 +193,8 @@ static int ntfs_read_block(struct page *page) int i, nr; unsigned char blocksize_bits; - ni = NTFS_I(page->mapping->host); + vi = page->mapping->host; + ni = NTFS_I(vi); vol = ni->vol; /* $MFT/$DATA must have its complete runlist in memory at all times. */ @@ -199,11 +213,28 @@ static int ntfs_read_block(struct page *page) bh = head = page_buffers(page); BUG_ON(!bh); + /* + * We may be racing with truncate. To avoid some of the problems we + * now take a snapshot of the various sizes and use those for the whole + * of the function. In case of an extending truncate it just means we + * may leave some buffers unmapped which are now allocated. This is + * not a problem since these buffers will just get mapped when a write + * occurs. In case of a shrinking truncate, we will detect this later + * on due to the runlist being incomplete and if the page is being + * fully truncated, truncate will throw it away as soon as we unlock + * it so no need to worry what we do with it. + */ iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); read_lock_irqsave(&ni->size_lock, flags); lblock = (ni->allocated_size + blocksize - 1) >> blocksize_bits; - zblock = (ni->initialized_size + blocksize - 1) >> blocksize_bits; + init_size = ni->initialized_size; + i_size = i_size_read(vi); read_unlock_irqrestore(&ni->size_lock, flags); + if (unlikely(init_size > i_size)) { + /* Race with shrinking truncate. */ + init_size = i_size; + } + zblock = (init_size + blocksize - 1) >> blocksize_bits; /* Loop through all the buffers in the page. */ rl = NULL; @@ -366,6 +397,8 @@ handle_zblock: */ static int ntfs_readpage(struct file *file, struct page *page) { + loff_t i_size; + struct inode *vi; ntfs_inode *ni, *base_ni; u8 *kaddr; ntfs_attr_search_ctx *ctx; @@ -384,14 +417,17 @@ retry_readpage: unlock_page(page); return 0; } - ni = NTFS_I(page->mapping->host); + vi = page->mapping->host; + ni = NTFS_I(vi); /* * Only $DATA attributes can be encrypted and only unnamed $DATA * attributes can be compressed. Index root can have the flags set but * this means to create compressed/encrypted files, not that the - * attribute is compressed/encrypted. + * attribute is compressed/encrypted. Note we need to check for + * AT_INDEX_ALLOCATION since this is the type of both directory and + * index inodes. */ - if (ni->type != AT_INDEX_ROOT) { + if (ni->type != AT_INDEX_ALLOCATION) { /* If attribute is encrypted, deny access, just like NT4. */ if (NInoEncrypted(ni)) { BUG_ON(ni->type != AT_DATA); @@ -456,7 +492,12 @@ retry_readpage: read_lock_irqsave(&ni->size_lock, flags); if (unlikely(attr_len > ni->initialized_size)) attr_len = ni->initialized_size; + i_size = i_size_read(vi); read_unlock_irqrestore(&ni->size_lock, flags); + if (unlikely(attr_len > i_size)) { + /* Race with shrinking truncate. */ + attr_len = i_size; + } kaddr = kmap_atomic(page, KM_USER0); /* Copy the data to the page. */ memcpy(kaddr, (u8*)ctx->attr + @@ -1341,9 +1382,11 @@ retry_writepage: * Only $DATA attributes can be encrypted and only unnamed $DATA * attributes can be compressed. Index root can have the flags set but * this means to create compressed/encrypted files, not that the - * attribute is compressed/encrypted. + * attribute is compressed/encrypted. Note we need to check for + * AT_INDEX_ALLOCATION since this is the type of both directory and + * index inodes. */ - if (ni->type != AT_INDEX_ROOT) { + if (ni->type != AT_INDEX_ALLOCATION) { /* If file is encrypted, deny access, just like NT4. */ if (NInoEncrypted(ni)) { unlock_page(page); @@ -1379,8 +1422,8 @@ retry_writepage: unsigned int ofs = i_size & ~PAGE_CACHE_MASK; kaddr = kmap_atomic(page, KM_USER0); memset(kaddr + ofs, 0, PAGE_CACHE_SIZE - ofs); - flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); } /* Handle mst protected attributes. */ if (NInoMstProtected(ni)) @@ -1443,34 +1486,33 @@ retry_writepage: BUG_ON(PageWriteback(page)); set_page_writeback(page); unlock_page(page); - /* - * Here, we do not need to zero the out of bounds area everytime - * because the below memcpy() already takes care of the - * mmap-at-end-of-file requirements. If the file is converted to a - * non-resident one, then the code path use is switched to the - * non-resident one where the zeroing happens on each ntfs_writepage() - * invocation. - */ attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); i_size = i_size_read(vi); if (unlikely(attr_len > i_size)) { + /* Race with shrinking truncate or a failed truncate. */ attr_len = i_size; - ctx->attr->data.resident.value_length = cpu_to_le32(attr_len); + /* + * If the truncate failed, fix it up now. If a concurrent + * truncate, we do its job, so it does not have to do anything. + */ + err = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, + attr_len); + /* Shrinking cannot fail. */ + BUG_ON(err); } kaddr = kmap_atomic(page, KM_USER0); /* Copy the data from the page to the mft record. */ memcpy((u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset), kaddr, attr_len); - flush_dcache_mft_record_page(ctx->ntfs_ino); /* Zero out of bounds area in the page cache page. */ memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); - flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); - + flush_dcache_mft_record_page(ctx->ntfs_ino); + flush_dcache_page(page); + /* We are done with the page. */ end_page_writeback(page); - - /* Mark the mft record dirty, so it gets written back. */ + /* Finally, mark the mft record dirty, so it gets written back. */ mark_mft_record_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); unmap_mft_record(base_ni); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index dc4bbe3acf5..7ec04513180 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1166,6 +1166,8 @@ err_out: * * Return 0 on success and -errno on error. In the error case, the inode will * have had make_bad_inode() executed on it. + * + * Note this cannot be called for AT_INDEX_ALLOCATION. */ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) { @@ -1242,8 +1244,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) } } /* - * The encryption flag set in an index root just means to - * compress all files. + * The compressed/sparse flag set in an index root just means + * to compress all files. */ if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { ntfs_error(vi->i_sb, "Found mst protected attribute " @@ -1319,8 +1321,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) "the mapping pairs array."); goto unm_err_out; } - if ((NInoCompressed(ni) || NInoSparse(ni)) && - ni->type != AT_INDEX_ROOT) { + if (NInoCompressed(ni) || NInoSparse(ni)) { if (a->data.non_resident.compression_unit != 4) { ntfs_error(vi->i_sb, "Found nonstandard " "compression unit (%u instead " diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h index 3288bcc2c4a..006946efca8 100644 --- a/fs/ntfs/malloc.h +++ b/fs/ntfs/malloc.h @@ -1,7 +1,7 @@ /* * malloc.h - NTFS kernel memory handling. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2004 Anton Altaparmakov + * Copyright (c) 2001-2005 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index f5b2ac92908..e2665d011d7 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c @@ -2,7 +2,7 @@ * runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project. * * Copyright (c) 2001-2005 Anton Altaparmakov - * Copyright (c) 2002 Richard Russon + * Copyright (c) 2002-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -214,8 +214,8 @@ static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src) static inline runlist_element *ntfs_rl_append(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { - BOOL right; - int magic; + BOOL right; /* Right end of @src needs merging. */ + int marker; /* End of the inserted runs. */ BUG_ON(!dst); BUG_ON(!src); @@ -236,18 +236,19 @@ static inline runlist_element *ntfs_rl_append(runlist_element *dst, if (right) __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); - magic = loc + ssize; + /* First run after the @src runs that have been inserted. */ + marker = loc + ssize + 1; /* Move the tail of @dst out of the way, then copy in @src. */ - ntfs_rl_mm(dst, magic + 1, loc + 1 + right, dsize - loc - 1 - right); + ntfs_rl_mm(dst, marker, loc + 1 + right, dsize - (loc + 1 + right)); ntfs_rl_mc(dst, loc + 1, src, 0, ssize); /* Adjust the size of the preceding hole. */ dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; /* We may have changed the length of the file, so fix the end marker */ - if (dst[magic + 1].lcn == LCN_ENOENT) - dst[magic + 1].vcn = dst[magic].vcn + dst[magic].length; + if (dst[marker].lcn == LCN_ENOENT) + dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; return dst; } @@ -279,18 +280,17 @@ static inline runlist_element *ntfs_rl_append(runlist_element *dst, static inline runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { - BOOL left = FALSE; - BOOL disc = FALSE; /* Discontinuity */ - BOOL hole = FALSE; /* Following a hole */ - int magic; + BOOL left = FALSE; /* Left end of @src needs merging. */ + BOOL disc = FALSE; /* Discontinuity between @dst and @src. */ + int marker; /* End of the inserted runs. */ BUG_ON(!dst); BUG_ON(!src); - /* disc => Discontinuity between the end of @dst and the start of @src. - * This means we might need to insert a hole. - * hole => @dst ends with a hole or an unmapped region which we can - * extend to match the discontinuity. */ + /* + * disc => Discontinuity between the end of @dst and the start of @src. + * This means we might need to insert a "not mapped" run. + */ if (loc == 0) disc = (src[0].vcn > 0); else { @@ -303,58 +303,49 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst, merged_length += src->length; disc = (src[0].vcn > dst[loc - 1].vcn + merged_length); - if (disc) - hole = (dst[loc - 1].lcn == LCN_HOLE); } - - /* Space required: @dst size + @src size, less one if we merged, plus - * one if there was a discontinuity, less one for a trailing hole. */ - dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc - hole); + /* + * Space required: @dst size + @src size, less one if we merged, plus + * one if there was a discontinuity. + */ + dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc); if (IS_ERR(dst)) return dst; /* * We are guaranteed to succeed from here so can start modifying the * original runlist. */ - if (left) __ntfs_rl_merge(dst + loc - 1, src); - - magic = loc + ssize - left + disc - hole; + /* + * First run after the @src runs that have been inserted. + * Nominally, @marker equals @loc + @ssize, i.e. location + number of + * runs in @src. However, if @left, then the first run in @src has + * been merged with one in @dst. And if @disc, then @dst and @src do + * not meet and we need an extra run to fill the gap. + */ + marker = loc + ssize - left + disc; /* Move the tail of @dst out of the way, then copy in @src. */ - ntfs_rl_mm(dst, magic, loc, dsize - loc); - ntfs_rl_mc(dst, loc + disc - hole, src, left, ssize - left); + ntfs_rl_mm(dst, marker, loc, dsize - loc); + ntfs_rl_mc(dst, loc + disc, src, left, ssize - left); - /* Adjust the VCN of the last run ... */ - if (dst[magic].lcn <= LCN_HOLE) - dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length; + /* Adjust the VCN of the first run after the insertion... */ + dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; /* ... and the length. */ - if (dst[magic].lcn == LCN_HOLE || dst[magic].lcn == LCN_RL_NOT_MAPPED) - dst[magic].length = dst[magic + 1].vcn - dst[magic].vcn; + if (dst[marker].lcn == LCN_HOLE || dst[marker].lcn == LCN_RL_NOT_MAPPED) + dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn; - /* Writing beyond the end of the file and there's a discontinuity. */ + /* Writing beyond the end of the file and there is a discontinuity. */ if (disc) { - if (hole) - dst[loc - 1].length = dst[loc].vcn - dst[loc - 1].vcn; - else { - if (loc > 0) { - dst[loc].vcn = dst[loc - 1].vcn + - dst[loc - 1].length; - dst[loc].length = dst[loc + 1].vcn - - dst[loc].vcn; - } else { - dst[loc].vcn = 0; - dst[loc].length = dst[loc + 1].vcn; - } - dst[loc].lcn = LCN_RL_NOT_MAPPED; + if (loc > 0) { + dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length; + dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; + } else { + dst[loc].vcn = 0; + dst[loc].length = dst[loc + 1].vcn; } - - magic += hole; - - if (dst[magic].lcn == LCN_ENOENT) - dst[magic].vcn = dst[magic - 1].vcn + - dst[magic - 1].length; + dst[loc].lcn = LCN_RL_NOT_MAPPED; } return dst; } @@ -385,9 +376,10 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst, static inline runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { - BOOL left = FALSE; - BOOL right; - int magic; + BOOL left = FALSE; /* Left end of @src needs merging. */ + BOOL right; /* Right end of @src needs merging. */ + int tail; /* Start of tail of @dst. */ + int marker; /* End of the inserted runs. */ BUG_ON(!dst); BUG_ON(!src); @@ -396,9 +388,10 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst, right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); if (loc > 0) left = ntfs_are_rl_mergeable(dst + loc - 1, src); - - /* Allocate some space. We'll need less if the left, right, or both - * ends were merged. */ + /* + * Allocate some space. We will need less if the left, right, or both + * ends were merged. + */ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right); if (IS_ERR(dst)) return dst; @@ -410,17 +403,28 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst, __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); if (left) __ntfs_rl_merge(dst + loc - 1, src); - - /* FIXME: What does this mean? (AIA) */ - magic = loc + ssize - left; + /* + * First run of @dst that needs to be moved out of the way to make + * space for the runs to be copied from @src, i.e. the first run of the + * tail of @dst. + */ + tail = loc + right + 1; + /* + * First run after the @src runs that have been inserted, i.e. where + * the tail of @dst needs to be moved to. + * Nominally, marker equals @loc + @ssize, i.e. location + number of + * runs in @src). However, if @left, then the first run in @src has + * been merged with one in @dst. + */ + marker = loc + ssize - left; /* Move the tail of @dst out of the way, then copy in @src. */ - ntfs_rl_mm(dst, magic, loc + right + 1, dsize - loc - right - 1); + ntfs_rl_mm(dst, marker, tail, dsize - tail); ntfs_rl_mc(dst, loc, src, left, ssize - left); - /* We may have changed the length of the file, so fix the end marker */ - if (dst[magic].lcn == LCN_ENOENT) - dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length; + /* We may have changed the length of the file, so fix the end marker. */ + if (dsize - tail > 0 && dst[marker].lcn == LCN_ENOENT) + dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; return dst; } diff --git a/fs/open.c b/fs/open.c index 2fac58c5191..f0d90cf0495 100644 --- a/fs/open.c +++ b/fs/open.c @@ -738,52 +738,15 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) return error; } -/* - * Note that while the flag value (low two bits) for sys_open means: - * 00 - read-only - * 01 - write-only - * 10 - read-write - * 11 - special - * it is changed into - * 00 - no permissions needed - * 01 - read-permission - * 10 - write-permission - * 11 - read-write - * for the internal routines (ie open_namei()/follow_link() etc). 00 is - * used by symlinks. - */ -struct file *filp_open(const char * filename, int flags, int mode) -{ - int namei_flags, error; - struct nameidata nd; - - namei_flags = flags; - if ((namei_flags+1) & O_ACCMODE) - namei_flags++; - if (namei_flags & O_TRUNC) - namei_flags |= 2; - - error = open_namei(filename, namei_flags, mode, &nd); - if (!error) - return dentry_open(nd.dentry, nd.mnt, flags); - - return ERR_PTR(error); -} - -EXPORT_SYMBOL(filp_open); - -struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) +static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, + int flags, struct file *f) { - struct file * f; struct inode *inode; int error; - error = -ENFILE; - f = get_empty_filp(); - if (!f) - goto cleanup_dentry; f->f_flags = flags; - f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; + f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | + FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); @@ -828,12 +791,63 @@ cleanup_all: f->f_vfsmnt = NULL; cleanup_file: put_filp(f); -cleanup_dentry: dput(dentry); mntput(mnt); return ERR_PTR(error); } +/* + * Note that while the flag value (low two bits) for sys_open means: + * 00 - read-only + * 01 - write-only + * 10 - read-write + * 11 - special + * it is changed into + * 00 - no permissions needed + * 01 - read-permission + * 10 - write-permission + * 11 - read-write + * for the internal routines (ie open_namei()/follow_link() etc). 00 is + * used by symlinks. + */ +struct file *filp_open(const char * filename, int flags, int mode) +{ + int namei_flags, error; + struct nameidata nd; + struct file *f; + + namei_flags = flags; + if ((namei_flags+1) & O_ACCMODE) + namei_flags++; + if (namei_flags & O_TRUNC) + namei_flags |= 2; + + error = -ENFILE; + f = get_empty_filp(); + if (f == NULL) + return ERR_PTR(error); + + error = open_namei(filename, namei_flags, mode, &nd); + if (!error) + return __dentry_open(nd.dentry, nd.mnt, flags, f); + + put_filp(f); + return ERR_PTR(error); +} +EXPORT_SYMBOL(filp_open); + +struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) +{ + int error; + struct file *f; + + error = -ENFILE; + f = get_empty_filp(); + if (f == NULL) + return ERR_PTR(error); + + return __dentry_open(dentry, mnt, flags, f); +} EXPORT_SYMBOL(dentry_open); /* diff --git a/fs/proc/array.c b/fs/proc/array.c index d88d518d30f..d84eecacbea 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -74,6 +74,7 @@ #include <linux/file.h> #include <linux/times.h> #include <linux/cpuset.h> +#include <linux/rcupdate.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -180,12 +181,14 @@ static inline char * task_state(struct task_struct *p, char *buffer) p->gid, p->egid, p->sgid, p->fsgid); read_unlock(&tasklist_lock); task_lock(p); + rcu_read_lock(); if (p->files) fdt = files_fdtable(p->files); buffer += sprintf(buffer, "FDSize:\t%d\n" "Groups:\t", fdt ? fdt->max_fds : 0); + rcu_read_unlock(); group_info = p->group_info; get_group_info(group_info); diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index c9f178fb494..c20babd6216 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -667,7 +667,7 @@ static int reiserfs_allocate_blocks_for_region(struct reiserfs_transaction_handl if (th->t_trans_id) { int err; // update any changes we made to blk count - reiserfs_update_sd(th, inode); + mark_inode_dirty(inode); err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + @@ -855,17 +855,18 @@ static int reiserfs_submit_file_region_for_write(struct reiserfs_transaction_han if (th->t_trans_id) { reiserfs_write_lock(inode->i_sb); - reiserfs_update_sd(th, inode); // And update on-disk metadata + // this sets the proper flags for O_SYNC to trigger a commit + mark_inode_dirty(inode); reiserfs_write_unlock(inode->i_sb); } else - inode->i_sb->s_op->dirty_inode(inode); + mark_inode_dirty(inode); sd_update = 1; } if (th->t_trans_id) { reiserfs_write_lock(inode->i_sb); if (!sd_update) - reiserfs_update_sd(th, inode); + mark_inode_dirty(inode); status = journal_end(th, th->t_super, th->t_blocks_allocated); if (status) retval = status; @@ -1320,7 +1321,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t return err; } reiserfs_update_inode_transaction(inode); - reiserfs_update_sd(&th, inode); + mark_inode_dirty(inode); err = journal_end(&th, inode->i_sb, 1); if (err) { reiserfs_write_unlock(inode->i_sb); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 1a8a1bf2154..d76ee6c4f9b 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -2639,6 +2639,12 @@ static int reiserfs_commit_write(struct file *f, struct page *page, } reiserfs_update_inode_transaction(inode); inode->i_size = pos; + /* + * this will just nest into our transaction. It's important + * to use mark_inode_dirty so the inode gets pushed around on the + * dirty lists, and so that O_SYNC works as expected + */ + mark_inode_dirty(inode); reiserfs_update_sd(&myth, inode); update_sd = 1; ret = journal_end(&myth, inode->i_sb, 1); @@ -2649,21 +2655,13 @@ static int reiserfs_commit_write(struct file *f, struct page *page, if (th) { reiserfs_write_lock(inode->i_sb); if (!update_sd) - reiserfs_update_sd(th, inode); + mark_inode_dirty(inode); ret = reiserfs_end_persistent_transaction(th); reiserfs_write_unlock(inode->i_sb); if (ret) goto out; } - /* we test for O_SYNC here so we can commit the transaction - ** for any packed tails the file might have had - */ - if (f && (f->f_flags & O_SYNC)) { - reiserfs_write_lock(inode->i_sb); - ret = reiserfs_commit_for_inode(inode); - reiserfs_write_unlock(inode->i_sb); - } out: return ret; |