diff options
Diffstat (limited to 'fs')
64 files changed, 566 insertions, 286 deletions
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 4f77f3c..af6952e 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -19,6 +19,7 @@ static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl); static void afs_fl_release_private(struct file_lock *fl); static struct workqueue_struct *afs_lock_manager; +static DEFINE_MUTEX(afs_lock_manager_mutex); static struct file_lock_operations afs_lock_ops = { .fl_copy_lock = afs_fl_copy_lock, @@ -30,12 +31,20 @@ static struct file_lock_operations afs_lock_ops = { */ static int afs_init_lock_manager(void) { + int ret; + + ret = 0; if (!afs_lock_manager) { - afs_lock_manager = create_singlethread_workqueue("kafs_lockd"); - if (!afs_lock_manager) - return -ENOMEM; + mutex_lock(&afs_lock_manager_mutex); + if (!afs_lock_manager) { + afs_lock_manager = + create_singlethread_workqueue("kafs_lockd"); + if (!afs_lock_manager) + ret = -ENOMEM; + } + mutex_unlock(&afs_lock_manager_mutex); } - return 0; + return ret; } /* @@ -68,6 +77,29 @@ static void afs_schedule_lock_extension(struct afs_vnode *vnode) } /* + * grant one or more locks (readlocks are allowed to jump the queue if the + * first lock in the queue is itself a readlock) + * - the caller must hold the vnode lock + */ +static void afs_grant_locks(struct afs_vnode *vnode, struct file_lock *fl) +{ + struct file_lock *p, *_p; + + list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks); + if (fl->fl_type == F_RDLCK) { + list_for_each_entry_safe(p, _p, &vnode->pending_locks, + fl_u.afs.link) { + if (p->fl_type == F_RDLCK) { + p->fl_u.afs.state = AFS_LOCK_GRANTED; + list_move_tail(&p->fl_u.afs.link, + &vnode->granted_locks); + wake_up(&p->fl_wait); + } + } + } +} + +/* * do work for a lock, including: * - probing for a lock we're waiting on but didn't get immediately * - extending a lock that's close to timing out @@ -172,8 +204,7 @@ void afs_lock_work(struct work_struct *work) struct file_lock, fl_u.afs.link) == fl) { fl->fl_u.afs.state = ret; if (ret == AFS_LOCK_GRANTED) - list_move_tail(&fl->fl_u.afs.link, - &vnode->granted_locks); + afs_grant_locks(vnode, fl); else list_del_init(&fl->fl_u.afs.link); wake_up(&fl->fl_wait); @@ -258,49 +289,50 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl) spin_lock(&vnode->lock); - if (list_empty(&vnode->pending_locks)) { - /* if there's no-one else with a lock on this vnode, then we - * need to ask the server for a lock */ - if (list_empty(&vnode->granted_locks)) { - _debug("not locked"); - ASSERTCMP(vnode->flags & - ((1 << AFS_VNODE_LOCKING) | - (1 << AFS_VNODE_READLOCKED) | - (1 << AFS_VNODE_WRITELOCKED)), ==, 0); - list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks); - set_bit(AFS_VNODE_LOCKING, &vnode->flags); - spin_unlock(&vnode->lock); + /* if we've already got a readlock on the server then we can instantly + * grant another readlock, irrespective of whether there are any + * pending writelocks */ + if (type == AFS_LOCK_READ && + vnode->flags & (1 << AFS_VNODE_READLOCKED)) { + _debug("instant readlock"); + ASSERTCMP(vnode->flags & + ((1 << AFS_VNODE_LOCKING) | + (1 << AFS_VNODE_WRITELOCKED)), ==, 0); + ASSERT(!list_empty(&vnode->granted_locks)); + goto sharing_existing_lock; + } - ret = afs_vnode_set_lock(vnode, key, type); - clear_bit(AFS_VNODE_LOCKING, &vnode->flags); - switch (ret) { - case 0: - goto acquired_server_lock; - case -EWOULDBLOCK: - spin_lock(&vnode->lock); - ASSERT(list_empty(&vnode->granted_locks)); - ASSERTCMP(vnode->pending_locks.next, ==, - &fl->fl_u.afs.link); - goto wait; - default: - spin_lock(&vnode->lock); - list_del_init(&fl->fl_u.afs.link); - spin_unlock(&vnode->lock); - goto error; - } - } + /* if there's no-one else with a lock on this vnode, then we need to + * ask the server for a lock */ + if (list_empty(&vnode->pending_locks) && + list_empty(&vnode->granted_locks)) { + _debug("not locked"); + ASSERTCMP(vnode->flags & + ((1 << AFS_VNODE_LOCKING) | + (1 << AFS_VNODE_READLOCKED) | + (1 << AFS_VNODE_WRITELOCKED)), ==, 0); + list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks); + set_bit(AFS_VNODE_LOCKING, &vnode->flags); + spin_unlock(&vnode->lock); - /* if we've already got a readlock on the server and no waiting - * writelocks, then we might be able to instantly grant another - * readlock */ - if (type == AFS_LOCK_READ && - vnode->flags & (1 << AFS_VNODE_READLOCKED)) { - _debug("instant readlock"); - ASSERTCMP(vnode->flags & - ((1 << AFS_VNODE_LOCKING) | - (1 << AFS_VNODE_WRITELOCKED)), ==, 0); - ASSERT(!list_empty(&vnode->granted_locks)); - goto sharing_existing_lock; + ret = afs_vnode_set_lock(vnode, key, type); + clear_bit(AFS_VNODE_LOCKING, &vnode->flags); + switch (ret) { + case 0: + _debug("acquired"); + goto acquired_server_lock; + case -EWOULDBLOCK: + _debug("would block"); + spin_lock(&vnode->lock); + ASSERT(list_empty(&vnode->granted_locks)); + ASSERTCMP(vnode->pending_locks.next, ==, + &fl->fl_u.afs.link); + goto wait; + default: + spin_lock(&vnode->lock); + list_del_init(&fl->fl_u.afs.link); + spin_unlock(&vnode->lock); + goto error; } } diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index e440a7b..a6c9078 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -115,6 +115,10 @@ #include <linux/dvb/video.h> #include <linux/lp.h> +#ifdef CONFIG_SPARC +#include <asm/fbio.h> +#endif + static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *f) { @@ -3157,12 +3161,9 @@ COMPATIBLE_IOCTL(SIOCSIWSENS) COMPATIBLE_IOCTL(SIOCGIWSENS) COMPATIBLE_IOCTL(SIOCSIWRANGE) COMPATIBLE_IOCTL(SIOCSIWPRIV) -COMPATIBLE_IOCTL(SIOCGIWPRIV) COMPATIBLE_IOCTL(SIOCSIWSTATS) -COMPATIBLE_IOCTL(SIOCGIWSTATS) COMPATIBLE_IOCTL(SIOCSIWAP) COMPATIBLE_IOCTL(SIOCGIWAP) -COMPATIBLE_IOCTL(SIOCSIWSCAN) COMPATIBLE_IOCTL(SIOCSIWRATE) COMPATIBLE_IOCTL(SIOCGIWRATE) COMPATIBLE_IOCTL(SIOCSIWRTS) @@ -3493,6 +3494,22 @@ IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32) /* loop */ IGNORE_IOCTL(LOOP_CLR_FD) + +#ifdef CONFIG_SPARC +/* Sparc framebuffers, handled in sbusfb_compat_ioctl() */ +IGNORE_IOCTL(FBIOGTYPE) +IGNORE_IOCTL(FBIOSATTR) +IGNORE_IOCTL(FBIOGATTR) +IGNORE_IOCTL(FBIOSVIDEO) +IGNORE_IOCTL(FBIOGVIDEO) +IGNORE_IOCTL(FBIOSCURPOS) +IGNORE_IOCTL(FBIOGCURPOS) +IGNORE_IOCTL(FBIOGCURMAX) +IGNORE_IOCTL(FBIOPUTCMAP32) +IGNORE_IOCTL(FBIOGETCMAP32) +IGNORE_IOCTL(FBIOSCURSOR32) +IGNORE_IOCTL(FBIOGCURSOR32) +#endif }; #define IOCTL_HASHSIZE 256 diff --git a/fs/dcookies.c b/fs/dcookies.c index c1208f5..792cbf5 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -20,6 +20,7 @@ #include <linux/capability.h> #include <linux/dcache.h> #include <linux/mm.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/dcookies.h> #include <linux/mutex.h> diff --git a/fs/direct-io.c b/fs/direct-io.c index 52bb263..6874785 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -974,6 +974,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, dio->get_block = get_block; dio->end_io = end_io; dio->map_bh.b_private = NULL; + dio->map_bh.b_state = 0; dio->final_block_in_bio = -1; dio->next_block_for_io = -1; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index b455919..2082daf 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -1670,9 +1670,10 @@ static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now, with a deadlk here, we'd have to generate something like grant_lock with the deadlk error.) */ -/* returns the highest requested mode of all blocked conversions */ +/* Returns the highest requested mode of all blocked conversions; sets + cw if there's a blocked conversion to DLM_LOCK_CW. */ -static int grant_pending_convert(struct dlm_rsb *r, int high) +static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw) { struct dlm_lkb *lkb, *s; int hi, demoted, quit, grant_restart, demote_restart; @@ -1709,6 +1710,9 @@ static int grant_pending_convert(struct dlm_rsb *r, int high) } hi = max_t(int, lkb->lkb_rqmode, hi); + + if (cw && lkb->lkb_rqmode == DLM_LOCK_CW) + *cw = 1; } if (grant_restart) @@ -1721,29 +1725,52 @@ static int grant_pending_convert(struct dlm_rsb *r, int high) return max_t(int, high, hi); } -static int grant_pending_wait(struct dlm_rsb *r, int high) +static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw) { struct dlm_lkb *lkb, *s; list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) { if (can_be_granted(r, lkb, 0, NULL)) grant_lock_pending(r, lkb); - else + else { high = max_t(int, lkb->lkb_rqmode, high); + if (lkb->lkb_rqmode == DLM_LOCK_CW) + *cw = 1; + } } return high; } +/* cw of 1 means there's a lock with a rqmode of DLM_LOCK_CW that's blocked + on either the convert or waiting queue. + high is the largest rqmode of all locks blocked on the convert or + waiting queue. */ + +static int lock_requires_bast(struct dlm_lkb *gr, int high, int cw) +{ + if (gr->lkb_grmode == DLM_LOCK_PR && cw) { + if (gr->lkb_highbast < DLM_LOCK_EX) + return 1; + return 0; + } + + if (gr->lkb_highbast < high && + !__dlm_compat_matrix[gr->lkb_grmode+1][high+1]) + return 1; + return 0; +} + static void grant_pending_locks(struct dlm_rsb *r) { struct dlm_lkb *lkb, *s; int high = DLM_LOCK_IV; + int cw = 0; DLM_ASSERT(is_master(r), dlm_dump_rsb(r);); - high = grant_pending_convert(r, high); - high = grant_pending_wait(r, high); + high = grant_pending_convert(r, high, &cw); + high = grant_pending_wait(r, high, &cw); if (high == DLM_LOCK_IV) return; @@ -1751,27 +1778,41 @@ static void grant_pending_locks(struct dlm_rsb *r) /* * If there are locks left on the wait/convert queue then send blocking * ASTs to granted locks based on the largest requested mode (high) - * found above. FIXME: highbast < high comparison not valid for PR/CW. + * found above. */ list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) { - if (lkb->lkb_bastaddr && (lkb->lkb_highbast < high) && - !__dlm_compat_matrix[lkb->lkb_grmode+1][high+1]) { - queue_bast(r, lkb, high); + if (lkb->lkb_bastaddr && lock_requires_bast(lkb, high, cw)) { + if (cw && high == DLM_LOCK_PR) + queue_bast(r, lkb, DLM_LOCK_CW); + else + queue_bast(r, lkb, high); lkb->lkb_highbast = high; } } } +static int modes_require_bast(struct dlm_lkb *gr, struct dlm_lkb *rq) +{ + if ((gr->lkb_grmode == DLM_LOCK_PR && rq->lkb_rqmode == DLM_LOCK_CW) || + (gr->lkb_grmode == DLM_LOCK_CW && rq->lkb_rqmode == DLM_LOCK_PR)) { + if (gr->lkb_highbast < DLM_LOCK_EX) + return 1; + return 0; + } + + if (gr->lkb_highbast < rq->lkb_rqmode && !modes_compat(gr, rq)) + return 1; + return 0; +} + static void send_bast_queue(struct dlm_rsb *r, struct list_head *head, struct dlm_lkb *lkb) { struct dlm_lkb *gr; list_for_each_entry(gr, head, lkb_statequeue) { - if (gr->lkb_bastaddr && - gr->lkb_highbast < lkb->lkb_rqmode && - !modes_compat(gr, lkb)) { + if (gr->lkb_bastaddr && modes_require_bast(gr, lkb)) { queue_bast(r, gr, lkb->lkb_rqmode); gr->lkb_highbast = lkb->lkb_rqmode; } @@ -2235,7 +2276,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb) before we try again to grant this one. */ if (is_demoted(lkb)) { - grant_pending_convert(r, DLM_LOCK_IV); + grant_pending_convert(r, DLM_LOCK_IV, NULL); if (_can_be_granted(r, lkb, 1)) { grant_lock(r, lkb); queue_cast(r, lkb, 0); diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index dd36273..9e9d2e8 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -313,6 +313,7 @@ static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port, in6_addr->sin6_port = cpu_to_be16(port); *addr_len = sizeof(struct sockaddr_in6); } + memset((char *)saddr + *addr_len, 0, sizeof(struct sockaddr_storage) - *addr_len); } /* Close a remote connection and tidy up */ @@ -332,8 +333,19 @@ static void close_connection(struct connection *con, bool and_other) __free_page(con->rx_page); con->rx_page = NULL; } - con->retries = 0; - mutex_unlock(&con->sock_mutex); + + /* If we are an 'othercon' then NULL the pointer to us + from the parent and tidy ourself up */ + if (test_bit(CF_IS_OTHERCON, &con->flags)) { + struct connection *parent = __nodeid2con(con->nodeid, 0); + parent->othercon = NULL; + kmem_cache_free(con_cache, con); + } + else { + /* Parent connections get reused */ + con->retries = 0; + mutex_unlock(&con->sock_mutex); + } } /* We only send shutdown messages to nodes that are not part of the cluster */ @@ -631,7 +643,7 @@ out_resched: out_close: mutex_unlock(&con->sock_mutex); - if (ret != -EAGAIN && !test_bit(CF_IS_OTHERCON, &con->flags)) { + if (ret != -EAGAIN) { close_connection(con, false); /* Reconnect when there is something to send */ } @@ -1122,8 +1134,6 @@ static int tcp_listen_for_all(void) log_print("Using TCP for communications"); - set_bit(CF_IS_OTHERCON, &con->flags); - sock = tcp_create_listen_sock(con, dlm_local_addr[0]); if (sock) { add_sock(sock, con); @@ -1407,7 +1417,7 @@ void dlm_lowcomms_stop(void) for (i = 0; i <= max_nodeid; i++) { con = __nodeid2con(i, 0); if (con) { - con->flags |= 0xFF; + con->flags |= 0x0F; if (con->sock) con->sock->sk->sk_user_data = NULL; } @@ -1423,8 +1433,6 @@ void dlm_lowcomms_stop(void) con = __nodeid2con(i, 0); if (con) { close_connection(con, true); - if (con->othercon) - kmem_cache_free(con_cache, con->othercon); kmem_cache_free(con_cache, con); } } diff --git a/fs/dlm/member.c b/fs/dlm/member.c index 073599d..d099775 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -56,8 +56,10 @@ static int dlm_add_member(struct dlm_ls *ls, int nodeid) return -ENOMEM; w = dlm_node_weight(ls->ls_name, nodeid); - if (w < 0) + if (w < 0) { + kfree(memb); return w; + } memb->nodeid = nodeid; memb->weight = w; diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index e3a1527..188b91c 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -386,8 +386,7 @@ static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) dlm_recover_process_copy(ls, rc_in); } -static int send_ls_not_ready(struct dlm_ls *ls, int nodeid, - struct dlm_rcom *rc_in) +static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) { struct dlm_rcom *rc; struct rcom_config *rf; @@ -395,7 +394,7 @@ static int send_ls_not_ready(struct dlm_ls *ls, int nodeid, char *mb; int mb_len = sizeof(struct dlm_rcom) + sizeof(struct rcom_config); - mh = dlm_lowcomms_get_buffer(nodeid, mb_len, ls->ls_allocation, &mb); + mh = dlm_lowcomms_get_buffer(nodeid, mb_len, GFP_NOFS, &mb); if (!mh) return -ENOBUFS; memset(mb, 0, mb_len); @@ -465,7 +464,7 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid) log_print("lockspace %x from %d type %x not found", hd->h_lockspace, nodeid, rc->rc_type); if (rc->rc_type == DLM_RCOM_STATUS) - send_ls_not_ready(ls, nodeid, rc); + send_ls_not_ready(nodeid, rc); return; } diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 0a50942..131954b 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -353,6 +353,10 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, ecryptfs_printk(KERN_DEBUG, "Is a symlink; returning\n"); goto out; } + if (special_file(lower_inode->i_mode)) { + ecryptfs_printk(KERN_DEBUG, "Is a special file; returning\n"); + goto out; + } if (!nd) { ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave" "as we *think* we are about to unlink\n"); diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index e557a67..a984972 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -813,6 +813,15 @@ out: return rc; } +static void do_sysfs_unregistration(void) +{ + sysfs_remove_file(&ecryptfs_subsys.kobj, + &sysfs_attr_version.attr); + sysfs_remove_file(&ecryptfs_subsys.kobj, + &sysfs_attr_version_str.attr); + subsystem_unregister(&ecryptfs_subsys); +} + static int __init ecryptfs_init(void) { int rc; @@ -851,6 +860,9 @@ static int __init ecryptfs_init(void) if (rc) { ecryptfs_printk(KERN_ERR, "Failure occured while attempting to " "initialize the eCryptfs netlink socket\n"); + do_sysfs_unregistration(); + unregister_filesystem(&ecryptfs_fs_type); + ecryptfs_free_kmem_caches(); } out: return rc; @@ -858,11 +870,7 @@ out: static void __exit ecryptfs_exit(void) { - sysfs_remove_file(&ecryptfs_subsys.kobj, - &sysfs_attr_version.attr); - sysfs_remove_file(&ecryptfs_subsys.kobj, - &sysfs_attr_version_str.attr); - subsystem_unregister(&ecryptfs_subsys); + do_sysfs_unregistration(); ecryptfs_release_messaging(ecryptfs_transport); unregister_filesystem(&ecryptfs_fs_type); ecryptfs_free_kmem_caches(); @@ -1084,9 +1084,12 @@ int flush_old_exec(struct linux_binprm * bprm) */ current->mm->task_size = TASK_SIZE; - if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || - file_permission(bprm->file, MAY_READ) || - (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { + if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) { + suid_keys(current); + set_dumpable(current->mm, suid_dumpable); + current->pdeath_signal = 0; + } else if (file_permission(bprm->file, MAY_READ) || + (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { suid_keys(current); set_dumpable(current->mm, suid_dumpable); } @@ -1177,8 +1180,10 @@ void compute_creds(struct linux_binprm *bprm) { int unsafe; - if (bprm->e_uid != current->uid) + if (bprm->e_uid != current->uid) { suid_keys(current); + current->pdeath_signal = 0; + } exec_keys(current); task_lock(current); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 68579a0..639a32c 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -580,7 +580,7 @@ static int ext2_check_descriptors (struct super_block * sb) return 0; } if (le32_to_cpu(gdp->bg_inode_table) < first_block || - le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > + le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group - 1 > last_block) { ext2_error (sb, "ext2_check_descriptors", diff --git a/fs/ext3/super.c b/fs/ext3/super.c index f0614e3..22cfdd6 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1221,7 +1221,7 @@ static int ext3_check_descriptors (struct super_block * sb) return 0; } if (le32_to_cpu(gdp->bg_inode_table) < first_block || - le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group > + le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group - 1 > last_block) { ext3_error (sb, "ext3_check_descriptors", diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 750c46f..78beb09 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -1544,7 +1544,7 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block, static void ext4_ext_put_in_cache(struct inode *inode, __u32 block, - __u32 len, __u32 start, int type) + __u32 len, ext4_fsblk_t start, int type) { struct ext4_ext_cache *cex; BUG_ON(len == 0); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 75adbb6..4550b83 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1283,7 +1283,7 @@ static int ext4_check_descriptors (struct super_block * sb) } inode_table = ext4_inode_table(sb, gdp); if (inode_table < first_block || - inode_table + sbi->s_itb_per_group > last_block) + inode_table + sbi->s_itb_per_group - 1 > last_block) { ext4_error (sb, "ext4_check_descriptors", "Inode table for group %d" diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index aff70f0..3b395c4 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -486,8 +486,8 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) gfs2_pin(sdp, bd->bd_bh); tr->tr_num_databuf_new++; } - sdp->sd_log_num_databuf++; gfs2_log_lock(sdp); + sdp->sd_log_num_databuf++; list_add(&le->le_list, &sdp->sd_log_le_databuf); gfs2_log_unlock(sdp); } @@ -523,7 +523,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) struct buffer_head *bh = NULL,*bh1 = NULL; struct gfs2_log_descriptor *ld; unsigned int limit; - unsigned int total_dbuf = sdp->sd_log_num_databuf; + unsigned int total_dbuf; unsigned int total_jdata = sdp->sd_log_num_jdata; unsigned int num, n; __be64 *ptr = NULL; @@ -535,6 +535,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) * into the log along with a header */ gfs2_log_lock(sdp); + total_dbuf = sdp->sd_log_num_databuf; bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, bd_le.le_list); while(total_dbuf) { @@ -653,6 +654,7 @@ static void databuf_lo_before_commit(struct gfs2_sbd *sdp) break; } bh = NULL; + BUG_ON(total_dbuf < num); total_dbuf -= num; total_jdata -= num; } diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index 6f006a80..4864659 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c @@ -82,19 +82,20 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) char *options, *o, *v; int error = 0; - /* If someone preloaded options, use those instead */ - spin_lock(&gfs2_sys_margs_lock); - if (!remount && gfs2_sys_margs) { - data = gfs2_sys_margs; - gfs2_sys_margs = NULL; - } - spin_unlock(&gfs2_sys_margs_lock); + if (!remount) { + /* If someone preloaded options, use those instead */ + spin_lock(&gfs2_sys_margs_lock); + if (gfs2_sys_margs) { + data = gfs2_sys_margs; + gfs2_sys_margs = NULL; + } + spin_unlock(&gfs2_sys_margs_lock); - /* Set some defaults */ - memset(args, 0, sizeof(struct gfs2_args)); - args->ar_num_glockd = GFS2_GLOCKD_DEFAULT; - args->ar_quota = GFS2_QUOTA_DEFAULT; - args->ar_data = GFS2_DATA_DEFAULT; + /* Set some defaults */ + args->ar_num_glockd = GFS2_GLOCKD_DEFAULT; + args->ar_quota = GFS2_QUOTA_DEFAULT; + args->ar_data = GFS2_DATA_DEFAULT; + } /* Split the options into tokens with the "," character and process them */ diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index ce90032..42a5f58 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -416,7 +416,7 @@ static int gfs2_prepare_write(struct file *file, struct page *page, error = gfs2_trans_begin(sdp, rblocks, 0); if (error) - goto out; + goto out_trans_fail; if (gfs2_is_stuffed(ip)) { if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { @@ -434,6 +434,7 @@ prepare_write: out: if (error) { gfs2_trans_end(sdp); +out_trans_fail: if (alloc_required) { gfs2_inplace_release(ip); out_qunlock: diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 1a5e8e8..94d76ac 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -177,8 +177,8 @@ static const u32 fsflags_to_gfs2[32] = { [5] = GFS2_DIF_APPENDONLY, [7] = GFS2_DIF_NOATIME, [12] = GFS2_DIF_EXHASH, - [14] = GFS2_DIF_JDATA, - [20] = GFS2_DIF_DIRECTIO, + [14] = GFS2_DIF_INHERIT_JDATA, + [20] = GFS2_DIF_INHERIT_DIRECTIO, }; static const u32 gfs2_to_fsflags[32] = { @@ -187,8 +187,6 @@ static const u32 gfs2_to_fsflags[32] = { [gfs2fl_AppendOnly] = FS_APPEND_FL, [gfs2fl_NoAtime] = FS_NOATIME_FL, [gfs2fl_ExHash] = FS_INDEX_FL, - [gfs2fl_Jdata] = FS_JOURNAL_DATA_FL, - [gfs2fl_Directio] = FS_DIRECTIO_FL, [gfs2fl_InheritDirectio] = FS_DIRECTIO_FL, [gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL, }; @@ -207,6 +205,12 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) return error; fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_di.di_flags); + if (!S_ISDIR(inode->i_mode)) { + if (ip->i_di.di_flags & GFS2_DIF_JDATA) + fsflags |= FS_JOURNAL_DATA_FL; + if (ip->i_di.di_flags & GFS2_DIF_DIRECTIO) + fsflags |= FS_DIRECTIO_FL; + } if (put_user(fsflags, ptr)) error = -EFAULT; @@ -270,13 +274,6 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) if ((new_flags ^ flags) == 0) goto out; - if (S_ISDIR(inode->i_mode)) { - if ((new_flags ^ flags) & GFS2_DIF_JDATA) - new_flags ^= (GFS2_DIF_JDATA|GFS2_DIF_INHERIT_JDATA); - if ((new_flags ^ flags) & GFS2_DIF_DIRECTIO) - new_flags ^= (GFS2_DIF_DIRECTIO|GFS2_DIF_INHERIT_DIRECTIO); - } - error = -EINVAL; if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET) goto out; @@ -315,11 +312,19 @@ out: static int gfs2_set_flags(struct file *filp, u32 __user *ptr) { + struct inode *inode = filp->f_path.dentry->d_inode; u32 fsflags, gfsflags; if (get_user(fsflags, ptr)) return -EFAULT; gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags); - return do_gfs2_set_flags(filp, gfsflags, ~0); + if (!S_ISDIR(inode->i_mode)) { + if (gfsflags & GFS2_DIF_INHERIT_JDATA) + gfsflags ^= (GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA); + if (gfsflags & GFS2_DIF_INHERIT_DIRECTIO) + gfsflags ^= (GFS2_DIF_DIRECTIO | GFS2_DIF_INHERIT_DIRECTIO); + return do_gfs2_set_flags(filp, gfsflags, ~0); + } + return do_gfs2_set_flags(filp, gfsflags, ~GFS2_DIF_JDATA); } static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) @@ -508,7 +513,7 @@ static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl) */ if (!sdp->sd_args.ar_localflocks) return -EINVAL; - return setlease(file, arg, fl); + return generic_setlease(file, arg, fl); } /** diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index e4e0406..ce48c45 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -863,16 +863,19 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) u64 no_addr; for(;;) { + if (goal >= rgd->rd_data) + break; goal = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, GFS2_BLKST_UNLINKED); - if (goal == 0) - return 0; + if (goal == BFITNOENT) + break; no_addr = goal + rgd->rd_data0; - if (no_addr <= *last_unlinked) + goal++; + if (no_addr < *last_unlinked) continue; *last_unlinked = no_addr; inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, - no_addr, -1); + no_addr, -1); if (!IS_ERR(inode)) return inode; } @@ -1313,7 +1316,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, bi->bi_len, blk, new_state); } - return (blk == BFITNOENT) ? 0 : (bi->bi_start * GFS2_NBBY) + blk; + return (blk == BFITNOENT) ? blk : (bi->bi_start * GFS2_NBBY) + blk; } /** @@ -1393,6 +1396,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) goal = rgd->rd_last_alloc_data; blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); + BUG_ON(blk == BFITNOENT); rgd->rd_last_alloc_data = blk; block = rgd->rd_data0 + blk; @@ -1437,6 +1441,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) goal = rgd->rd_last_alloc_meta; blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); + BUG_ON(blk == BFITNOENT); rgd->rd_last_alloc_meta = blk; block = rgd->rd_data0 + blk; @@ -1478,6 +1483,7 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) blk = rgblk_search(rgd, rgd->rd_last_alloc_meta, GFS2_BLKST_FREE, GFS2_BLKST_DINODE); + BUG_ON(blk == BFITNOENT); rgd->rd_last_alloc_meta = blk; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 95c72aa..043b470 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -846,6 +846,15 @@ root_found: goto out_no_root; if (!inode->i_op) goto out_bad_root; + + /* Make sure the root inode is a directory */ + if (!S_ISDIR(inode->i_mode)) { + printk(KERN_WARNING + "isofs_fill_super: root inode is not a directory. " + "Corrupted media?\n"); + goto out_iput; + } + /* get the root dentry */ s->s_root = d_alloc_root(inode); if (!(s->s_root)) diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 143c553..504643f 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -84,7 +84,7 @@ static int jffs2_garbage_collect_thread(void *_c) set_freezable(); for (;;) { allow_signal(SIGHUP); - + again: if (!jffs2_thread_should_wake(c)) { set_current_state (TASK_INTERRUPTIBLE); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); @@ -95,9 +95,6 @@ static int jffs2_garbage_collect_thread(void *_c) schedule(); } - if (try_to_freeze()) - continue; - /* This thread is purely an optimisation. But if it runs when other things could be running, it actually makes things a lot worse. Use yield() and put it at the back of the runqueue @@ -112,6 +109,9 @@ static int jffs2_garbage_collect_thread(void *_c) siginfo_t info; unsigned long signr; + if (try_to_freeze()) + goto again; + signr = dequeue_signal_lock(current, ¤t->blocked, &info); switch(signr) { diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 25126a0..bc5509f 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -139,6 +139,11 @@ static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_nod #define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE) #define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0) +/* Dirent nodes should be REF_PRISTINE only if they are not a deletion + dirent. Deletion dirents should be REF_NORMAL so that GC gets to + throw them away when appropriate */ +#define dirent_node_state(rd) ( (je32_to_cpu((rd)->ino)?REF_PRISTINE:REF_NORMAL) ) + /* NB: REF_PRISTINE for an inode-less node (ref->next_in_ino == NULL) indicates it is an unknown node of type JFFS2_NODETYPE_RWCOMPAT_COPY, so it'll get copied. If you need to do anything different to GC inode-less nodes, then diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 7b36378..b5baa35 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -104,7 +104,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info if (crc != tn->data_crc) { JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", - ofs, tn->data_crc, crc); + ref_offset(ref), tn->data_crc, crc); return 1; } @@ -613,7 +613,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r jeb->unchecked_size -= len; c->used_size += len; c->unchecked_size -= len; - ref->flash_offset = ref_offset(ref) | REF_PRISTINE; + ref->flash_offset = ref_offset(ref) | dirent_node_state(rd); spin_unlock(&c->erase_completion_lock); } diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 2a1c976..6c75cd4 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -1049,7 +1049,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo return -ENOMEM; } - fd->raw = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rd->totlen)), ic); + fd->raw = jffs2_link_node_ref(c, jeb, ofs | dirent_node_state(rd), + PAD(je32_to_cpu(rd->totlen)), ic); fd->next = NULL; fd->version = je32_to_cpu(rd->version); diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index c9fe0ab..bc61859 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -173,6 +173,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 flash_ofs |= REF_NORMAL; } fn->raw = jffs2_add_physical_node_ref(c, flash_ofs, PAD(sizeof(*ri)+datalen), f->inocache); + if (IS_ERR(fn->raw)) { + void *hold_err = fn->raw; + /* Release the full_dnode which is now useless, and return */ + jffs2_free_full_dnode(fn); + return ERR_PTR(PTR_ERR(hold_err)); + } fn->ofs = je32_to_cpu(ri->offset); fn->size = je32_to_cpu(ri->dsize); fn->frags = 0; @@ -290,7 +296,14 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff return ERR_PTR(ret?ret:-EIO); } /* Mark the space used */ - fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | REF_PRISTINE, PAD(sizeof(*rd)+namelen), f->inocache); + fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | dirent_node_state(rd), + PAD(sizeof(*rd)+namelen), f->inocache); + if (IS_ERR(fd->raw)) { + void *hold_err = fd->raw; + /* Release the full_dirent which is now useless, and return */ + jffs2_free_full_dirent(fd); + return ERR_PTR(PTR_ERR(hold_err)); + } if (retried) { jffs2_dbg_acct_sanity_check(c,NULL); diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index b3efa45..a21e4bc 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -335,10 +335,10 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call) /* * Deferred lock request handling for non-blocking lock */ -static u32 +static __be32 nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block) { - u32 status = nlm_lck_denied_nolocks; + __be32 status = nlm_lck_denied_nolocks; block->b_flags |= B_QUEUED; @@ -352,7 +352,7 @@ nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block) status = nlm_drop_reply; } dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n", - block, block->b_flags, status); + block, block->b_flags, ntohl(status)); return status; } @@ -1324,7 +1324,7 @@ int fcntl_getlease(struct file *filp) } /** - * setlease - sets a lease on an open file + * generic_setlease - sets a lease on an open file * @filp: file pointer * @arg: type of lease to obtain * @flp: input - file_lock to use, output - file_lock inserted @@ -1334,7 +1334,7 @@ int fcntl_getlease(struct file *filp) * * Called with kernel lock held. */ -int setlease(struct file *filp, long arg, struct file_lock **flp) +int generic_setlease(struct file *filp, long arg, struct file_lock **flp) { struct file_lock *fl, **before, **my_before = NULL, *lease; struct dentry *dentry = filp->f_path.dentry; @@ -1419,7 +1419,7 @@ int setlease(struct file *filp, long arg, struct file_lock **flp) out: return error; } -EXPORT_SYMBOL(setlease); +EXPORT_SYMBOL(generic_setlease); /** * vfs_setlease - sets a lease on an open file @@ -1456,7 +1456,7 @@ int vfs_setlease(struct file *filp, long arg, struct file_lock **lease) if (filp->f_op && filp->f_op->setlease) error = filp->f_op->setlease(filp, arg, lease); else - error = setlease(filp, arg, lease); + error = generic_setlease(filp, arg, lease); unlock_kernel(); return error; diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index 551e0ba..df6d60b 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -726,9 +726,6 @@ ncp_del_file_or_subdir2(struct ncp_server *server, __le32 dirent; if (!inode) { -#ifdef CONFIG_NCPFS_DEBUGDENTRY - PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n"); -#endif return 0xFF; /* Any error */ } volnum = NCP_FINFO(inode)->volNumber; diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 20ac403..c55a761 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -20,10 +20,8 @@ #include "delegation.h" #include "internal.h" -static void nfs_free_delegation(struct nfs_delegation *delegation) +static void nfs_do_free_delegation(struct nfs_delegation *delegation) { - if (delegation->cred) - put_rpccred(delegation->cred); kfree(delegation); } @@ -31,7 +29,18 @@ static void nfs_free_delegation_callback(struct rcu_head *head) { struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu); - nfs_free_delegation(delegation); + nfs_do_free_delegation(delegation); +} + +static void nfs_free_delegation(struct nfs_delegation *delegation) +{ + struct rpc_cred *cred; + + cred = rcu_dereference(delegation->cred); + rcu_assign_pointer(delegation->cred, NULL); + call_rcu(&delegation->rcu, nfs_free_delegation_callback); + if (cred) + put_rpccred(cred); } static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) @@ -166,7 +175,7 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * int res = 0; res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); - call_rcu(&delegation->rcu, nfs_free_delegation_callback); + nfs_free_delegation(delegation); return res; } @@ -448,7 +457,7 @@ restart: spin_unlock(&clp->cl_lock); rcu_read_unlock(); if (delegation != NULL) - call_rcu(&delegation->rcu, nfs_free_delegation_callback); + nfs_free_delegation(delegation); goto restart; } rcu_read_unlock(); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bca6cdc..71a49c3 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -468,7 +468,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str ctx->lockowner = current->files; ctx->error = 0; ctx->dir_cookie = 0; - kref_init(&ctx->kref); + atomic_set(&ctx->count, 1); } return ctx; } @@ -476,21 +476,18 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) { if (ctx != NULL) - kref_get(&ctx->kref); + atomic_inc(&ctx->count); return ctx; } -static void nfs_free_open_context(struct kref *kref) +void put_nfs_open_context(struct nfs_open_context *ctx) { - struct nfs_open_context *ctx = container_of(kref, - struct nfs_open_context, kref); + struct inode *inode = ctx->path.dentry->d_inode; - if (!list_empty(&ctx->list)) { - struct inode *inode = ctx->path.dentry->d_inode; - spin_lock(&inode->i_lock); - list_del(&ctx->list); - spin_unlock(&inode->i_lock); - } + if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) + return; + list_del(&ctx->list); + spin_unlock(&inode->i_lock); if (ctx->state != NULL) nfs4_close_state(&ctx->path, ctx->state, ctx->mode); if (ctx->cred != NULL) @@ -500,11 +497,6 @@ static void nfs_free_open_context(struct kref *kref) kfree(ctx); } -void put_nfs_open_context(struct nfs_open_context *ctx) -{ - kref_put(&ctx->kref, nfs_free_open_context); -} - /* * Ensure that mmap has a recent RPC credential for use when writing out * shared pages diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 7f86e65..aea76d0 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -175,10 +175,8 @@ static void nfs_expire_automounts(struct work_struct *work) void nfs_release_automount_timer(void) { - if (list_empty(&nfs_automount_list)) { - cancel_delayed_work(&nfs_automount_task); - flush_scheduled_work(); - } + if (list_empty(&nfs_automount_list)) + cancel_delayed_work_sync(&nfs_automount_task); } /* diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6ca2795..62b3ae2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -332,11 +332,9 @@ static int can_open_cached(struct nfs4_state *state, int mode) switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { case FMODE_READ: ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; - ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; break; case FMODE_WRITE: ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; - ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; break; case FMODE_READ|FMODE_WRITE: ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; @@ -1260,7 +1258,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); switch (task->tk_status) { case 0: - nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags); + nfs_set_open_stateid(state, &calldata->res.stateid, 0); renew_lease(server, calldata->timestamp); break; case -NFS4ERR_STALE_STATEID: @@ -1286,23 +1284,19 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) .rpc_cred = state->owner->so_cred, }; int clear_rd, clear_wr, clear_rdwr; - int mode; if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) return; - mode = FMODE_READ|FMODE_WRITE; clear_rd = clear_wr = clear_rdwr = 0; spin_lock(&state->owner->so_lock); /* Calculate the change in open mode */ if (state->n_rdwr == 0) { if (state->n_rdonly == 0) { - mode &= ~FMODE_READ; clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); } if (state->n_wronly == 0) { - mode &= ~FMODE_WRITE; clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); } @@ -1314,9 +1308,13 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) return; } nfs_fattr_init(calldata->res.fattr); - if (mode != 0) + if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; - calldata->arg.open_flags = mode; + calldata->arg.open_flags = FMODE_READ; + } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { + msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; + calldata->arg.open_flags = FMODE_WRITE; + } calldata->timestamp = jiffies; rpc_call_setup(task, &msg, 0); } diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 0505ca1..3ea352d 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c @@ -127,16 +127,15 @@ nfs4_schedule_state_renewal(struct nfs_client *clp) void nfs4_renewd_prepare_shutdown(struct nfs_server *server) { - flush_scheduled_work(); + cancel_delayed_work(&server->nfs_client->cl_renewd); } void nfs4_kill_renewd(struct nfs_client *clp) { down_read(&clp->cl_sem); - cancel_delayed_work(&clp->cl_renewd); + cancel_delayed_work_sync(&clp->cl_renewd); up_read(&clp->cl_sem); - flush_scheduled_work(); } /* diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e9662ba..3e4adf8 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -341,8 +341,6 @@ nfs4_state_set_mode_locked(struct nfs4_state *state, mode_t mode) else list_move_tail(&state->open_states, &state->owner->so_states); } - if (mode == 0) - list_del_init(&state->inode_states); state->state = mode; } @@ -415,8 +413,7 @@ void nfs4_put_open_state(struct nfs4_state *state) if (!atomic_dec_and_lock(&state->count, &owner->so_lock)) return; spin_lock(&inode->i_lock); - if (!list_empty(&state->inode_states)) - list_del(&state->inode_states); + list_del(&state->inode_states); list_del(&state->open_states); spin_unlock(&inode->i_lock); spin_unlock(&owner->so_lock); diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 2d295dd..cba899a 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -564,9 +564,10 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) /* flags */ err = get_int(&mesg, &an_int); - if (err == -ENOENT) + if (err == -ENOENT) { + err = 0; set_bit(CACHE_NEGATIVE, &exp.h.flags); - else { + } else { if (err || an_int < 0) goto out; exp.ex_flags= an_int; diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 2cf9a9a..2ccffde 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -138,7 +138,7 @@ idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, char idstr[11]; qword_add(bpp, blen, ent->authname); - snprintf(idstr, sizeof(idstr), "%d", ent->id); + snprintf(idstr, sizeof(idstr), "%u", ent->id); qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); qword_add(bpp, blen, idstr); @@ -165,7 +165,7 @@ idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) return 0; } ent = container_of(h, struct ent, h); - seq_printf(m, "%s %s %d", ent->authname, + seq_printf(m, "%s %s %u", ent->authname, ent->type == IDMAP_TYPE_GROUP ? "group" : "user", ent->id); if (test_bit(CACHE_VALID, &h->flags)) @@ -349,7 +349,7 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) ent->type == IDMAP_TYPE_GROUP ? "group" : "user", ent->name); if (test_bit(CACHE_VALID, &h->flags)) - seq_printf(m, " %d", ent->id); + seq_printf(m, " %u", ent->id); seq_printf(m, "\n"); return 0; } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3c62712..29b7e63 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -100,7 +100,15 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &open->op_iattr, &resfh, open->op_createmode, - (u32 *)open->op_verf.data, &open->op_truncate, &created); + (u32 *)open->op_verf.data, + &open->op_truncate, &created); + + /* If we ever decide to use different attrs to store the + * verifier in nfsd_create_v3, then we'll need to change this + */ + if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0) + open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS | + FATTR4_WORD1_TIME_MODIFY); } else { status = nfsd_lookup(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &resfh); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b3d55c6..8ef0964 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2450,7 +2450,7 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ } static void -nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr, +nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_secinfo *secinfo) { int i = 0; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index ee96a89..a0c2b25 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1309,7 +1309,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, if (createmode == NFS3_CREATE_EXCLUSIVE) { /* solaris7 gets confused (bugid 4218508) if these have - * the high bit set, so just clear the high bits. + * the high bit set, so just clear the high bits. If this is + * ever changed to use different attrs for storing the + * verifier, then do_open_lookup() will also need to be fixed + * accordingly. */ v_mtime = verifier[0]&0x7fffffff; v_atime = verifier[1]&0x7fffffff; diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index f5e11f4..4f51766 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -3731,7 +3731,6 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, { int status; struct buffer_head *last_eb_bh = NULL; - struct buffer_head *bh = NULL; struct ocfs2_insert_type insert = {0, }; struct ocfs2_extent_rec rec; @@ -3783,9 +3782,6 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, ocfs2_extent_map_insert_rec(inode, &rec); bail: - if (bh) - brelse(bh); - if (last_eb_bh) brelse(last_eb_bh); diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index f0bdfd9..685c180 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -854,17 +854,25 @@ static void o2net_sendpage(struct o2net_sock_container *sc, struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); ssize_t ret; - - mutex_lock(&sc->sc_send_lock); - ret = sc->sc_sock->ops->sendpage(sc->sc_sock, - virt_to_page(kmalloced_virt), - (long)kmalloced_virt & ~PAGE_MASK, - size, MSG_DONTWAIT); - mutex_unlock(&sc->sc_send_lock); - if (ret != size) { + while (1) { + mutex_lock(&sc->sc_send_lock); + ret = sc->sc_sock->ops->sendpage(sc->sc_sock, + virt_to_page(kmalloced_virt), + (long)kmalloced_virt & ~PAGE_MASK, + size, MSG_DONTWAIT); + mutex_unlock(&sc->sc_send_lock); + if (ret == size) + break; + if (ret == (ssize_t)-EAGAIN) { + mlog(0, "sendpage of size %zu to " SC_NODEF_FMT + " returned EAGAIN\n", size, SC_NODEF_ARGS(sc)); + cond_resched(); + continue; + } mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT " failed with %zd\n", size, SC_NODEF_ARGS(sc), ret); o2net_ensure_shutdown(nn, sc, 0); + break; } } diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index c4034f6..4ffa715be 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -187,6 +187,7 @@ int ocfs2_update_inode_atime(struct inode *inode, int ret; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); handle_t *handle; + struct ocfs2_dinode *di = (struct ocfs2_dinode *) bh->b_data; mlog_entry_void(); @@ -197,11 +198,27 @@ int ocfs2_update_inode_atime(struct inode *inode, goto out; } + ret = ocfs2_journal_access(handle, inode, bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + + /* + * Don't use ocfs2_mark_inode_dirty() here as we don't always + * have i_mutex to guard against concurrent changes to other + * inode fields. + */ inode->i_atime = CURRENT_TIME; - ret = ocfs2_mark_inode_dirty(handle, inode, bh); + di->i_atime = cpu_to_le64(inode->i_atime.tv_sec); + di->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); + + ret = ocfs2_journal_dirty(handle, bh); if (ret < 0) mlog_errno(ret); +out_commit: ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); out: mlog_exit(ret); @@ -1011,6 +1028,11 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) } if (size_change && attr->ia_size != i_size_read(inode)) { + if (attr->ia_size > sb->s_maxbytes) { + status = -EFBIG; + goto bail_unlock; + } + if (i_size_read(inode) > attr->ia_size) status = ocfs2_truncate_file(inode, bh, attr->ia_size); else @@ -1516,7 +1538,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct buffer_head *di_bh = NULL; handle_t *handle; - unsigned long long max_off = ocfs2_max_file_offset(inode->i_sb->s_blocksize_bits); + unsigned long long max_off = inode->i_sb->s_maxbytes; if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) return -EROFS; @@ -1942,7 +1964,7 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos, } dst = kmap_atomic(page, KM_USER0); - memcpy(dst + (pos & (PAGE_CACHE_SIZE - 1)), buf, bytes); + memcpy(dst + (pos & (loff_t)(PAGE_CACHE_SIZE - 1)), buf, bytes); kunmap_atomic(dst, KM_USER0); flush_dcache_page(page); ocfs2_put_write_source(user_page); diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index d430fda..701e6d0 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -1080,6 +1080,7 @@ static int ocfs2_rename(struct inode *old_dir, struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir, // this is the 1st dirent bh nlink_t old_dir_nlink = old_dir->i_nlink; + struct ocfs2_dinode *old_di; /* At some point it might be nice to break this function up a * bit. */ @@ -1354,7 +1355,20 @@ static int ocfs2_rename(struct inode *old_dir, old_inode->i_ctime = CURRENT_TIME; mark_inode_dirty(old_inode); - ocfs2_mark_inode_dirty(handle, old_inode, old_inode_bh); + + status = ocfs2_journal_access(handle, old_inode, old_inode_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status >= 0) { + old_di = (struct ocfs2_dinode *) old_inode_bh->b_data; + + old_di->i_ctime = cpu_to_le64(old_inode->i_ctime.tv_sec); + old_di->i_ctime_nsec = cpu_to_le32(old_inode->i_ctime.tv_nsec); + + status = ocfs2_journal_dirty(handle, old_inode_bh); + if (status < 0) + mlog_errno(status); + } else + mlog_errno(status); /* now that the name has been added to new_dir, remove the old name */ status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh); diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 5cc90a4..5830785 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -494,16 +494,16 @@ static inline unsigned int ocfs2_page_index_to_clusters(struct super_block *sb, /* * Find the 1st page index which covers the given clusters. */ -static inline unsigned long ocfs2_align_clusters_to_page_index(struct super_block *sb, +static inline pgoff_t ocfs2_align_clusters_to_page_index(struct super_block *sb, u32 clusters) { unsigned int cbits = OCFS2_SB(sb)->s_clustersize_bits; - unsigned long index = clusters; + pgoff_t index = clusters; if (PAGE_CACHE_SHIFT > cbits) { - index = clusters >> (PAGE_CACHE_SHIFT - cbits); + index = (pgoff_t)clusters >> (PAGE_CACHE_SHIFT - cbits); } else if (PAGE_CACHE_SHIFT < cbits) { - index = clusters << (cbits - PAGE_CACHE_SHIFT); + index = (pgoff_t)clusters << (cbits - PAGE_CACHE_SHIFT); } return index; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 200c7d4..f2fc9a7 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -316,39 +316,51 @@ static void ocfs2_destroy_inode(struct inode *inode) kmem_cache_free(ocfs2_inode_cachep, OCFS2_I(inode)); } -/* From xfs_super.c:xfs_max_file_offset - * Copyright (c) 2000-2004 Silicon Graphics, Inc. - */ -unsigned long long ocfs2_max_file_offset(unsigned int blockshift) +static unsigned long long ocfs2_max_file_offset(unsigned int bbits, + unsigned int cbits) { - unsigned int pagefactor = 1; - unsigned int bitshift = BITS_PER_LONG - 1; - - /* Figure out maximum filesize, on Linux this can depend on - * the filesystem blocksize (on 32 bit platforms). - * __block_prepare_write does this in an [unsigned] long... - * page->index << (PAGE_CACHE_SHIFT - bbits) - * So, for page sized blocks (4K on 32 bit platforms), - * this wraps at around 8Tb (hence MAX_LFS_FILESIZE which is - * (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) - * but for smaller blocksizes it is less (bbits = log2 bsize). - * Note1: get_block_t takes a long (implicit cast from above) - * Note2: The Large Block Device (LBD and HAVE_SECTOR_T) patch - * can optionally convert the [unsigned] long from above into - * an [unsigned] long long. + unsigned int bytes = 1 << cbits; + unsigned int trim = bytes; + unsigned int bitshift = 32; + + /* + * i_size and all block offsets in ocfs2 are always 64 bits + * wide. i_clusters is 32 bits, in cluster-sized units. So on + * 64 bit platforms, cluster size will be the limiting factor. */ #if BITS_PER_LONG == 32 # if defined(CONFIG_LBD) BUILD_BUG_ON(sizeof(sector_t) != 8); - pagefactor = PAGE_CACHE_SIZE; - bitshift = BITS_PER_LONG; + /* + * We might be limited by page cache size. + */ + if (bytes > PAGE_CACHE_SIZE) { + bytes = PAGE_CACHE_SIZE; + trim = 1; + /* + * Shift by 31 here so that we don't get larger than + * MAX_LFS_FILESIZE + */ + bitshift = 31; + } # else - pagefactor = PAGE_CACHE_SIZE >> (PAGE_CACHE_SHIFT - blockshift); + /* + * We are limited by the size of sector_t. Use block size, as + * that's what we expose to the VFS. + */ + bytes = 1 << bbits; + trim = 1; + bitshift = 31; # endif #endif - return (((unsigned long long)pagefactor) << bitshift) - 1; + /* + * Trim by a whole cluster when we can actually approach the + * on-disk limits. Otherwise we can overflow i_clusters when + * an extent start is at the max offset. + */ + return (((unsigned long long)bytes) << bitshift) - trim; } static int ocfs2_remount(struct super_block *sb, int *flags, char *data) @@ -1259,8 +1271,8 @@ static int ocfs2_initialize_super(struct super_block *sb, int sector_size) { int status = 0; - int i; - struct ocfs2_dinode *di = NULL; + int i, cbits, bbits; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; struct inode *inode = NULL; struct buffer_head *bitmap_bh = NULL; struct ocfs2_journal *journal; @@ -1279,9 +1291,12 @@ static int ocfs2_initialize_super(struct super_block *sb, sb->s_fs_info = osb; sb->s_op = &ocfs2_sops; sb->s_export_op = &ocfs2_export_ops; + sb->s_time_gran = 1; sb->s_flags |= MS_NOATIME; /* this is needed to support O_LARGEFILE */ - sb->s_maxbytes = ocfs2_max_file_offset(sb->s_blocksize_bits); + cbits = le32_to_cpu(di->id2.i_super.s_clustersize_bits); + bbits = le32_to_cpu(di->id2.i_super.s_blocksize_bits); + sb->s_maxbytes = ocfs2_max_file_offset(bbits, cbits); osb->sb = sb; /* Save off for ocfs2_rw_direct */ @@ -1341,8 +1356,6 @@ static int ocfs2_initialize_super(struct super_block *sb, goto bail; } - di = (struct ocfs2_dinode *)bh->b_data; - osb->max_slots = le16_to_cpu(di->id2.i_super.s_max_slots); if (osb->max_slots > OCFS2_MAX_SLOTS || osb->max_slots == 0) { mlog(ML_ERROR, "Invalid number of node slots (%u)\n", diff --git a/fs/ocfs2/super.h b/fs/ocfs2/super.h index 3b9cb3d..783f527 100644 --- a/fs/ocfs2/super.h +++ b/fs/ocfs2/super.h @@ -45,6 +45,4 @@ void __ocfs2_abort(struct super_block *sb, #define ocfs2_abort(sb, fmt, args...) __ocfs2_abort(sb, __PRETTY_FUNCTION__, fmt, ##args) -unsigned long long ocfs2_max_file_offset(unsigned int blockshift); - #endif /* OCFS2_SUPER_H */ @@ -256,24 +256,26 @@ static long do_sys_truncate(const char __user * path, loff_t length) if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; - /* - * Make sure that there are no leases. - */ - error = break_lease(inode, FMODE_WRITE); + error = get_write_access(inode); if (error) goto dput_and_out; - error = get_write_access(inode); + /* + * Make sure that there are no leases. get_write_access() protects + * against the truncate racing with a lease-granting setlease(). + */ + error = break_lease(inode, FMODE_WRITE); if (error) - goto dput_and_out; + goto put_write_and_out; error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); error = do_truncate(nd.dentry, length, 0, NULL); } - put_write_access(inode); +put_write_and_out: + put_write_access(inode); dput_and_out: path_release(&nd); out: diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 4ccec4c..5567ec0 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -203,6 +203,7 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, Sector sect; struct solaris_x86_vtoc *v; int i; + short max_nparts; v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, §); if (!v) @@ -218,7 +219,9 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, put_dev_sector(sect); return; } - for (i=0; i<SOLARIS_X86_NUMSLICE && state->next<state->limit; i++) { + /* Ensure we can handle previous case of VTOC with 8 entries gracefully */ + max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8; + for (i=0; i<max_nparts && state->next<state->limit; i++) { struct solaris_x86_slice *s = &v->v_slice[i]; if (s->s_size == 0) continue; diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c index 123f8b4..794118d 100644 --- a/fs/partitions/sun.c +++ b/fs/partitions/sun.c @@ -19,34 +19,47 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) Sector sect; struct sun_disklabel { unsigned char info[128]; /* Informative text string */ - unsigned char spare0[14]; - struct sun_info { - unsigned char spare1; - unsigned char id; - unsigned char spare2; - unsigned char flags; - } infos[8]; - unsigned char spare[246]; /* Boot information etc. */ + struct sun_vtoc { + __be32 version; /* Layout version */ + char volume[8]; /* Volume name */ + __be16 nparts; /* Number of partitions */ + struct sun_info { /* Partition hdrs, sec 2 */ + __be16 id; + __be16 flags; + } infos[8]; + __be16 padding; /* Alignment padding */ + __be32 bootinfo[3]; /* Info needed by mboot */ + __be32 sanity; /* To verify vtoc sanity */ + __be32 reserved[10]; /* Free space */ + __be32 timestamp[8]; /* Partition timestamp */ + } vtoc; + __be32 write_reinstruct; /* sectors to skip, writes */ + __be32 read_reinstruct; /* sectors to skip, reads */ + unsigned char spare[148]; /* Padding */ __be16 rspeed; /* Disk rotational speed */ __be16 pcylcount; /* Physical cylinder count */ __be16 sparecyl; /* extra sects per cylinder */ - unsigned char spare2[4]; /* More magic... */ + __be16 obs1; /* gap1 */ + __be16 obs2; /* gap2 */ __be16 ilfact; /* Interleave factor */ __be16 ncyl; /* Data cylinder count */ __be16 nacyl; /* Alt. cylinder count */ __be16 ntrks; /* Tracks per cylinder */ __be16 nsect; /* Sectors per track */ - unsigned char spare3[4]; /* Even more magic... */ + __be16 obs3; /* bhead - Label head offset */ + __be16 obs4; /* ppart - Physical Partition */ struct sun_partition { __be32 start_cylinder; __be32 num_sectors; } partitions[8]; __be16 magic; /* Magic number */ __be16 csum; /* Label xor'd checksum */ - } * label; + } * label; struct sun_partition *p; unsigned long spc; char b[BDEVNAME_SIZE]; + int use_vtoc; + int nparts; label = (struct sun_disklabel *)read_dev_sector(bdev, 0, §); if (!label) @@ -70,9 +83,22 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) return 0; } - /* All Sun disks have 8 partition entries */ + /* Check to see if we can use the VTOC table */ + use_vtoc = ((be32_to_cpu(label->vtoc.sanity) == SUN_VTOC_SANITY) && + (be32_to_cpu(label->vtoc.version) == 1) && + (be16_to_cpu(label->vtoc.nparts) <= 8)); + + /* Use 8 partition entries if not specified in validated VTOC */ + nparts = (use_vtoc) ? be16_to_cpu(label->vtoc.nparts) : 8; + + /* + * So that old Linux-Sun partitions continue to work, + * alow the VTOC to be used under the additional condition ... + */ + use_vtoc = use_vtoc || !(label->vtoc.sanity | + label->vtoc.version | label->vtoc.nparts); spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect); - for (i = 0; i < 8; i++, p++) { + for (i = 0; i < nparts; i++, p++) { unsigned long st_sector; unsigned int num_sectors; @@ -81,10 +107,12 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) if (num_sectors) { put_partition(state, slot, st_sector, num_sectors); state->parts[slot].flags = 0; - if (label->infos[i].id == LINUX_RAID_PARTITION) - state->parts[slot].flags |= ADDPART_FLAG_RAID; - if (label->infos[i].id == SUN_WHOLE_DISK) - state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK; + if (use_vtoc) { + if (be16_to_cpu(label->vtoc.infos[i].id) == LINUX_RAID_PARTITION) + state->parts[slot].flags |= ADDPART_FLAG_RAID; + else if (be16_to_cpu(label->vtoc.infos[i].id) == SUN_WHOLE_DISK) + state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK; + } } slot++; } diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h index b1b19fd..7f864d1 100644 --- a/fs/partitions/sun.h +++ b/fs/partitions/sun.h @@ -3,5 +3,6 @@ */ #define SUN_LABEL_MAGIC 0xDABE +#define SUN_VTOC_SANITY 0x600DDEEE int sun_partition(struct parsed_partitions *state, struct block_device *bdev); @@ -255,7 +255,7 @@ void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) /** * generic_pipe_buf_confirm - verify contents of the pipe buffer - * @pipe: the pipe that the buffer belongs to + * @info: the pipe that the buffer belongs to * @buf: the buffer to confirm * * Description: diff --git a/fs/proc/base.c b/fs/proc/base.c index 3c77d5a..19489b0 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -927,7 +927,7 @@ static const struct file_operations proc_pid_sched_operations = { .read = seq_read, .write = sched_write, .llseek = seq_lseek, - .release = seq_release, + .release = single_release, }; #endif diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 94e2c1a..a5b0dfd 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -386,6 +386,19 @@ static const struct file_operations proc_reg_file_ops = { .release = proc_reg_release, }; +#ifdef CONFIG_COMPAT +static const struct file_operations proc_reg_file_ops_no_compat = { + .llseek = proc_reg_llseek, + .read = proc_reg_read, + .write = proc_reg_write, + .poll = proc_reg_poll, + .unlocked_ioctl = proc_reg_unlocked_ioctl, + .mmap = proc_reg_mmap, + .open = proc_reg_open, + .release = proc_reg_release, +}; +#endif + struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, struct proc_dir_entry *de) { @@ -413,8 +426,15 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, if (de->proc_iops) inode->i_op = de->proc_iops; if (de->proc_fops) { - if (S_ISREG(inode->i_mode)) - inode->i_fop = &proc_reg_file_ops; + if (S_ISREG(inode->i_mode)) { +#ifdef CONFIG_COMPAT + if (!de->proc_fops->compat_ioctl) + inode->i_fop = + &proc_reg_file_ops_no_compat; + else +#endif + inode->i_fop = &proc_reg_file_ops; + } else inode->i_fop = de->proc_fops; } @@ -387,7 +387,7 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t return ret; } -#if defined(CONFIG_X86_64) || defined(CONFIG_IA64) +#if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT) /* * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64) * and is necessary due to alignment problems. diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index cad2b7a..237fe8b 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -295,5 +295,10 @@ unsigned long ramfs_nommu_get_unmapped_area(struct file *file, */ int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma) { - return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS; + if (!(vma->vm_flags & VM_SHARED)) + return -ENOSYS; + + file_accessed(file); + vma->vm_ops = &generic_file_vm_ops; + return 0; } diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index b6f1259..981027d 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -1042,7 +1042,8 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st pos = I_UNFM_NUM(&s_ih); while (le_ih_k_offset (&s_ih) + (pos - 1) * blk_size > n_new_file_length) { - __u32 *unfm, block; + __le32 *unfm; + __u32 block; /* Each unformatted block deletion may involve one additional * bitmap block into the transaction, thereby the initial @@ -1052,7 +1053,7 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st break; } - unfm = (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + pos - 1; + unfm = (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + pos - 1; block = get_block_num(unfm, 0); if (block != 0) { diff --git a/fs/signalfd.c b/fs/signalfd.c index 3b07f26..7b941ab 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -320,7 +320,7 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas if (sizemask != sizeof(sigset_t) || copy_from_user(&sigmask, user_mask, sizeof(sigmask))) - return error = -EINVAL; + return -EINVAL; sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); signotset(&sigmask); diff --git a/fs/splice.c b/fs/splice.c index 0a09732..c010a72 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -164,7 +164,7 @@ static const struct pipe_buf_operations user_page_pipe_buf_ops = { * @spd: data to fill * * Description: - * @spd contains a map of pages and len/offset tupples, a long with + * @spd contains a map of pages and len/offset tuples, along with * the struct pipe_buf_operations associated with these pages. This * function will link that data to the pipe. * @@ -1000,7 +1000,7 @@ static long do_splice_to(struct file *in, loff_t *ppos, * Description: * This is a special case helper to splice directly between two * points, without requiring an explicit pipe. Internally an allocated - * pipe is cached in the process, and reused during the life time of + * pipe is cached in the process, and reused during the lifetime of * that process. * */ diff --git a/fs/timerfd.c b/fs/timerfd.c index af9eca5..61983f3 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -95,7 +95,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, { struct timerfd_ctx *ctx = file->private_data; ssize_t res; - u32 ticks = 0; + u64 ticks = 0; DECLARE_WAITQUEUE(wait, current); if (count < sizeof(ticks)) @@ -130,7 +130,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, * callback to avoid DoS attacks specifying a very * short timer period. */ - ticks = (u32) + ticks = (u64) hrtimer_forward(&ctx->tmr, hrtimer_cb_get_time(&ctx->tmr), ctx->tintv); @@ -140,7 +140,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, } spin_unlock_irq(&ctx->wqh.lock); if (ticks) - res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks); + res = put_user(ticks, (u64 __user *) buf) ? -EFAULT: sizeof(ticks); return res; } diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 0d2c416..1652b2c 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1127,13 +1127,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) } inode->i_uid = le32_to_cpu(fe->uid); - if (inode->i_uid == -1 || UDF_QUERY_FLAG(inode->i_sb, - UDF_FLAG_UID_IGNORE)) + if (inode->i_uid == -1 || + UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_IGNORE) || + UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_SET)) inode->i_uid = UDF_SB(inode->i_sb)->s_uid; inode->i_gid = le32_to_cpu(fe->gid); - if (inode->i_gid == -1 || UDF_QUERY_FLAG(inode->i_sb, - UDF_FLAG_GID_IGNORE)) + if (inode->i_gid == -1 || + UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_IGNORE) || + UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_SET)) inode->i_gid = UDF_SB(inode->i_sb)->s_gid; inode->i_nlink = le16_to_cpu(fe->fileLinkCount); diff --git a/fs/udf/super.c b/fs/udf/super.c index 7b30964..382be7b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -366,11 +366,13 @@ static int udf_parse_options(char *options, struct udf_options *uopt) if (match_int(args, &option)) return 0; uopt->gid = option; + uopt->flags |= (1 << UDF_FLAG_GID_SET); break; case Opt_uid: if (match_int(args, &option)) return 0; uopt->uid = option; + uopt->flags |= (1 << UDF_FLAG_UID_SET); break; case Opt_umask: if (match_octal(args, &option)) diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 3e937d3..3c29820 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -24,6 +24,8 @@ #define UDF_FLAG_UID_IGNORE 12 /* use sb uid instead of on disk uid */ #define UDF_FLAG_GID_FORGET 13 #define UDF_FLAG_GID_IGNORE 14 +#define UDF_FLAG_UID_SET 15 +#define UDF_FLAG_GID_SET 16 #define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001 #define UDF_PART_FLAG_UNALLOC_TABLE 0x0002 diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 141cf15..42319d7 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -139,7 +139,7 @@ STATIC int xfs_inumbers_fmt_compat( long count, long *written) { - compat_xfs_inogrp_t *p32 = ubuffer; + compat_xfs_inogrp_t __user *p32 = ubuffer; long i; for (i = 0; i < count; i++) { @@ -444,7 +444,7 @@ xfs_compat_ioctl( case XFS_IOC_FSINUMBERS_32: cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq); return xfs_ioc_bulkstat_compat(XFS_BHVTOI(VNHEAD(vp))->i_mount, - cmd, (void*)arg); + cmd, (void __user*)arg); case XFS_IOC_FD_TO_HANDLE_32: case XFS_IOC_PATH_TO_HANDLE_32: case XFS_IOC_PATH_TO_FSHANDLE_32: |