diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2006-03-23 14:50:51 +0000 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2006-03-23 14:50:51 +0000 |
commit | b4d8d1a93c6ea042b29bb66fbb1cf6bc556c18f7 (patch) | |
tree | 030ef62361042d1a034087ad9a726db3b57bba72 /fs | |
parent | bb8047d3540affd6b8c2adac3fe792e07143be0f (diff) | |
parent | 2e6e33bab6e1996a5dec9108fb467b52b841e7a8 (diff) |
Merge branch 'master' of /usr/src/ntfs-2.6/
Diffstat (limited to 'fs')
108 files changed, 1477 insertions, 1127 deletions
diff --git a/fs/9p/9p.c b/fs/9p/9p.c index 1a6d08761f3..f86a28d1d6a 100644 --- a/fs/9p/9p.c +++ b/fs/9p/9p.c @@ -111,7 +111,6 @@ static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc, if (!rc) return; - dprintk(DEBUG_9P, "tcall id %d rcall id %d\n", tc->id, rc->id); v9ses = a; if (rc->id == RCLUNK) v9fs_put_idpool(fid, &v9ses->fidpool); diff --git a/fs/9p/fid.c b/fs/9p/fid.c index eda449778fa..c4d13bf904d 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -1,7 +1,7 @@ /* * V9FS FID Management * - * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +40,7 @@ * */ -static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) +int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) { struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid, @@ -57,7 +57,6 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) } fid->uid = current->uid; - fid->pid = current->pid; list_add(&fid->list, fid_list); return 0; } @@ -68,14 +67,11 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) * */ -struct v9fs_fid *v9fs_fid_create(struct dentry *dentry, - struct v9fs_session_info *v9ses, int fid, int create) +struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid) { struct v9fs_fid *new; - dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n", - dentry, fid, create); - + dprintk(DEBUG_9P, "fid create fid %d\n", fid); new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); if (new == NULL) { dprintk(DEBUG_ERROR, "Out of Memory\n"); @@ -85,19 +81,13 @@ struct v9fs_fid *v9fs_fid_create(struct dentry *dentry, new->fid = fid; new->v9ses = v9ses; new->fidopen = 0; - new->fidcreate = create; new->fidclunked = 0; new->iounit = 0; new->rdir_pos = 0; new->rdir_fcall = NULL; + INIT_LIST_HEAD(&new->list); - if (v9fs_fid_insert(new, dentry) == 0) - return new; - else { - dprintk(DEBUG_ERROR, "Problems inserting to dentry\n"); - kfree(new); - return NULL; - } + return new; } /** @@ -113,140 +103,29 @@ void v9fs_fid_destroy(struct v9fs_fid *fid) } /** - * v9fs_fid_walk_up - walks from the process current directory - * up to the specified dentry. - */ -static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) -{ - int fidnum, cfidnum, err; - struct v9fs_fid *cfid; - struct dentry *cde; - struct v9fs_session_info *v9ses; - - v9ses = v9fs_inode2v9ses(current->fs->pwd->d_inode); - cfid = v9fs_fid_lookup(current->fs->pwd); - if (cfid == NULL) { - dprintk(DEBUG_ERROR, "process cwd doesn't have a fid\n"); - return ERR_PTR(-ENOENT); - } - - cfidnum = cfid->fid; - cde = current->fs->pwd; - /* TODO: take advantage of multiwalk */ - - fidnum = v9fs_get_idpool(&v9ses->fidpool); - if (fidnum < 0) { - dprintk(DEBUG_ERROR, "could not get a new fid num\n"); - err = -ENOENT; - goto clunk_fid; - } - - while (cde != dentry) { - if (cde == cde->d_parent) { - dprintk(DEBUG_ERROR, "can't find dentry\n"); - err = -ENOENT; - goto clunk_fid; - } - - err = v9fs_t_walk(v9ses, cfidnum, fidnum, "..", NULL); - if (err < 0) { - dprintk(DEBUG_ERROR, "problem walking to parent\n"); - goto clunk_fid; - } - - cfidnum = fidnum; - cde = cde->d_parent; - } - - return v9fs_fid_create(dentry, v9ses, fidnum, 0); - -clunk_fid: - v9fs_t_clunk(v9ses, fidnum); - return ERR_PTR(err); -} - -/** * v9fs_fid_lookup - retrieve the right fid from a particular dentry * @dentry: dentry to look for fid in * @type: intent of lookup (operation or traversal) * - * search list of fids associated with a dentry for a fid with a matching - * thread id or uid. If that fails, look up the dentry's parents to see if you - * can find a matching fid. + * find a fid in the dentry + * + * TODO: only match fids that have the same uid as current user * */ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) { struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; - struct v9fs_fid *current_fid = NULL; - struct v9fs_fid *temp = NULL; struct v9fs_fid *return_fid = NULL; dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); - if (fid_list) { - list_for_each_entry_safe(current_fid, temp, fid_list, list) { - if (!current_fid->fidcreate) { - return_fid = current_fid; - break; - } - } - - if (!return_fid) - return_fid = current_fid; - } - - /* we are at the root but didn't match */ - if ((!return_fid) && (dentry->d_parent == dentry)) { - /* TODO: clone attach with new uid */ - return_fid = current_fid; - } + if (fid_list) + return_fid = list_entry(fid_list->next, struct v9fs_fid, list); if (!return_fid) { - struct dentry *par = current->fs->pwd->d_parent; - int count = 1; - while (par != NULL) { - if (par == dentry) - break; - count++; - if (par == par->d_parent) { - dprintk(DEBUG_ERROR, - "got to root without finding dentry\n"); - break; - } - par = par->d_parent; - } - -/* XXX - there may be some duplication we can get rid of */ - if (par == dentry) { - return_fid = v9fs_fid_walk_up(dentry); - if (IS_ERR(return_fid)) - return_fid = NULL; - } + dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n"); } return return_fid; } - -struct v9fs_fid *v9fs_fid_get_created(struct dentry *dentry) -{ - struct list_head *fid_list; - struct v9fs_fid *fid, *ftmp, *ret; - - dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); - fid_list = (struct list_head *)dentry->d_fsdata; - ret = NULL; - if (fid_list) { - list_for_each_entry_safe(fid, ftmp, fid_list, list) { - if (fid->fidcreate && fid->pid == current->pid) { - list_del(&fid->list); - ret = fid; - break; - } - } - } - - dprintk(DEBUG_9P, "return %p\n", ret); - return ret; -} diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 84c673a44c8..1fc2dd08d75 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h @@ -33,7 +33,6 @@ struct v9fs_fid { u32 fid; unsigned char fidopen; /* set when fid is opened */ - unsigned char fidcreate; /* set when fid was just created */ unsigned char fidclunked; /* set when fid has already been clunked */ struct v9fs_qid qid; @@ -45,7 +44,6 @@ struct v9fs_fid { struct v9fs_fcall *rdir_fcall; /* management stuff */ - pid_t pid; /* thread associated with this fid */ uid_t uid; /* user associated with this fid */ /* private data */ @@ -56,5 +54,5 @@ struct v9fs_fid { struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); struct v9fs_fid *v9fs_fid_get_created(struct dentry *); void v9fs_fid_destroy(struct v9fs_fid *fid); -struct v9fs_fid *v9fs_fid_create(struct dentry *, - struct v9fs_session_info *v9ses, int fid, int create); +struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid); +int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry); diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c index 1a28ef97a3d..5b2ce21b10f 100644 --- a/fs/9p/trans_fd.c +++ b/fs/9p/trans_fd.c @@ -80,6 +80,7 @@ static int v9fs_fd_send(struct v9fs_transport *trans, void *v, int len) if (!trans || trans->status != Connected || !ts) return -EIO; + oldfs = get_fs(); set_fs(get_ds()); /* The cast to a user pointer is valid due to the set_fs() */ ret = vfs_write(ts->out_file, (void __user *)v, len, &ts->out_file->f_pos); diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index ef338654914..61352491ba3 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -397,6 +397,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses, } if (v9ses->afid != ~0) { + dprintk(DEBUG_ERROR, "afid not equal to ~0\n"); if (v9fs_t_clunk(v9ses, v9ses->afid)) dprintk(DEBUG_ERROR, "clunk failed\n"); } diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 69cf2905dc9..a759278acaa 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -51,3 +51,4 @@ int v9fs_dir_release(struct inode *inode, struct file *filp); int v9fs_file_open(struct inode *inode, struct file *file); void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat); void v9fs_dentry_release(struct dentry *); +int v9fs_uflags2omode(int uflags); diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 2dd806dac9f..12c9cc926b7 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -43,47 +43,18 @@ #include "fid.h" /** - * v9fs_dentry_validate - VFS dcache hook to validate cache - * @dentry: dentry that is being validated - * @nd: path data + * v9fs_dentry_delete - called when dentry refcount equals 0 + * @dentry: dentry in question * - * dcache really shouldn't be used for 9P2000 as at all due to - * potential attached semantics to directory traversal (walk). - * - * FUTURE: look into how to use dcache to allow multi-stage - * walks in Plan 9 & potential for better dcache operation which - * would remain valid for Plan 9 semantics. Older versions - * had validation via stat for those interested. However, since - * stat has the same approximate overhead as walk there really - * is no difference. The only improvement would be from a - * time-decay cache like NFS has and that undermines the - * synchronous nature of 9P2000. + * By returning 1 here we should remove cacheing of unused + * dentry components. * */ -static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd) +int v9fs_dentry_delete(struct dentry *dentry) { - struct dentry *dc = current->fs->pwd; - - dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); - if (v9fs_fid_lookup(dentry)) { - dprintk(DEBUG_VFS, "VALID\n"); - return 1; - } - - while (dc != NULL) { - if (dc == dentry) { - dprintk(DEBUG_VFS, "VALID\n"); - return 1; - } - if (dc == dc->d_parent) - break; - - dc = dc->d_parent; - } - - dprintk(DEBUG_VFS, "INVALID\n"); - return 0; + dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); + return 1; } /** @@ -118,6 +89,6 @@ void v9fs_dentry_release(struct dentry *dentry) } struct dentry_operations v9fs_dentry_operations = { - .d_revalidate = v9fs_dentry_validate, + .d_delete = v9fs_dentry_delete, .d_release = v9fs_dentry_release, }; diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index ae6d032b9b5..cd5eeb032d6 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -202,7 +202,6 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) filp->private_data = NULL; } - d_drop(filp->f_dentry); return 0; } diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index c7e14d91721..de3a129698d 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -53,94 +53,70 @@ int v9fs_file_open(struct inode *inode, struct file *file) { struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); - struct v9fs_fid *v9fid, *fid; + struct v9fs_fid *vfid; struct v9fs_fcall *fcall = NULL; - int open_mode = 0; - unsigned int iounit = 0; - int newfid = -1; - long result = -1; + int omode; + int fid = V9FS_NOFID; + int err; dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); - v9fid = v9fs_fid_get_created(file->f_dentry); - if (!v9fid) - v9fid = v9fs_fid_lookup(file->f_dentry); - - if (!v9fid) { + vfid = v9fs_fid_lookup(file->f_dentry); + if (!vfid) { dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); return -EBADF; } - if (!v9fid->fidcreate) { - fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); - if (fid == NULL) { - dprintk(DEBUG_ERROR, "Out of Memory\n"); - return -ENOMEM; - } - - fid->fidopen = 0; - fid->fidcreate = 0; - fid->fidclunked = 0; - fid->iounit = 0; - fid->v9ses = v9ses; - - newfid = v9fs_get_idpool(&v9ses->fidpool); - if (newfid < 0) { + fid = v9fs_get_idpool(&v9ses->fidpool); + if (fid < 0) { eprintk(KERN_WARNING, "newfid fails!\n"); return -ENOSPC; } - result = - v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); - - if (result < 0) { - v9fs_put_idpool(newfid, &v9ses->fidpool); + err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, NULL); + if (err < 0) { dprintk(DEBUG_ERROR, "rewalk didn't work\n"); - return -EBADF; + goto put_fid; + } + + vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); + if (vfid == NULL) { + dprintk(DEBUG_ERROR, "out of memory\n"); + goto clunk_fid; } - fid->fid = newfid; - v9fid = fid; /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ /* translate open mode appropriately */ - open_mode = file->f_flags & 0x3; + omode = v9fs_uflags2omode(file->f_flags); + err = v9fs_t_open(v9ses, fid, omode, &fcall); + if (err < 0) { + PRINT_FCALL_ERROR("open failed", fcall); + goto destroy_vfid; + } - if (file->f_flags & O_EXCL) - open_mode |= V9FS_OEXCL; + file->private_data = vfid; + vfid->fid = fid; + vfid->fidopen = 1; + vfid->fidclunked = 0; + vfid->iounit = fcall->params.ropen.iounit; + vfid->rdir_pos = 0; + vfid->rdir_fcall = NULL; + vfid->filp = file; + kfree(fcall); - if (v9ses->extended) { - if (file->f_flags & O_TRUNC) - open_mode |= V9FS_OTRUNC; + return 0; - if (file->f_flags & O_APPEND) - open_mode |= V9FS_OAPPEND; - } +destroy_vfid: + v9fs_fid_destroy(vfid); - result = v9fs_t_open(v9ses, newfid, open_mode, &fcall); - if (result < 0) { - PRINT_FCALL_ERROR("open failed", fcall); - kfree(fcall); - return result; - } +clunk_fid: + v9fs_t_clunk(v9ses, fid); - iounit = fcall->params.ropen.iounit; +put_fid: + v9fs_put_idpool(fid, &v9ses->fidpool); kfree(fcall); - } else { - /* create case */ - newfid = v9fid->fid; - iounit = v9fid->iounit; - v9fid->fidcreate = 0; - } - - file->private_data = v9fid; - - v9fid->rdir_pos = 0; - v9fid->rdir_fcall = NULL; - v9fid->fidopen = 1; - v9fid->filp = file; - v9fid->iounit = iounit; - return 0; + return err; } /** @@ -289,9 +265,7 @@ v9fs_file_write(struct file *filp, const char __user * data, total += result; } while (count); - if(inode->i_mapping->nrpages) invalidate_inode_pages2(inode->i_mapping); - return total; } diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 63e5b0398e8..651a9e14d9a 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -125,6 +125,38 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) return res; } +int v9fs_uflags2omode(int uflags) +{ + int ret; + + ret = 0; + switch (uflags&3) { + default: + case O_RDONLY: + ret = V9FS_OREAD; + break; + + case O_WRONLY: + ret = V9FS_OWRITE; + break; + + case O_RDWR: + ret = V9FS_ORDWR; + break; + } + + if (uflags & O_EXCL) + ret |= V9FS_OEXCL; + + if (uflags & O_TRUNC) + ret |= V9FS_OTRUNC; + + if (uflags & O_APPEND) + ret |= V9FS_OAPPEND; + + return ret; +} + /** * v9fs_blank_wstat - helper function to setup a 9P stat structure * @v9ses: 9P session info (for determining extended mode) @@ -163,7 +195,7 @@ v9fs_blank_wstat(struct v9fs_wstat *wstat) struct inode *v9fs_get_inode(struct super_block *sb, int mode) { - struct inode *inode = NULL; + struct inode *inode; struct v9fs_session_info *v9ses = sb->s_fs_info; dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); @@ -222,171 +254,133 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) return inode; } -/** - * v9fs_create - helper function to create files and directories - * @dir: directory inode file is being created in - * @file_dentry: dentry file is being created in - * @perm: permissions file is being created with - * @open_mode: resulting open mode for file - * - */ - static int -v9fs_create(struct inode *dir, - struct dentry *file_dentry, - unsigned int perm, unsigned int open_mode) +v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, + u32 perm, u8 mode, u32 *fidp, struct v9fs_qid *qid, u32 *iounit) { - struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); - struct super_block *sb = dir->i_sb; - struct v9fs_fid *dirfid = - v9fs_fid_lookup(file_dentry->d_parent); - struct v9fs_fid *fid = NULL; - struct inode *file_inode = NULL; - struct v9fs_fcall *fcall = NULL; - struct v9fs_qid qid; - int dirfidnum = -1; - long newfid = -1; - int result = 0; - unsigned int iounit = 0; - int wfidno = -1; + u32 fid; int err; + struct v9fs_fcall *fcall; - perm = unixmode2p9mode(v9ses, perm); - - dprintk(DEBUG_VFS, "dir: %p dentry: %p perm: %o mode: %o\n", dir, - file_dentry, perm, open_mode); - - if (!dirfid) - return -EBADF; - - dirfidnum = dirfid->fid; - if (dirfidnum < 0) { - dprintk(DEBUG_ERROR, "No fid for the directory #%lu\n", - dir->i_ino); - return -EBADF; - } - - if (file_dentry->d_inode) { - dprintk(DEBUG_ERROR, - "Odd. There is an inode for dir %lu, name :%s:\n", - dir->i_ino, file_dentry->d_name.name); - return -EEXIST; - } - - newfid = v9fs_get_idpool(&v9ses->fidpool); - if (newfid < 0) { + fid = v9fs_get_idpool(&v9ses->fidpool); + if (fid < 0) { eprintk(KERN_WARNING, "no free fids available\n"); return -ENOSPC; } - result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); - if (result < 0) { + err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); + if (err < 0) { PRINT_FCALL_ERROR("clone error", fcall); - v9fs_put_idpool(newfid, &v9ses->fidpool); - newfid = -1; - goto CleanUpFid; + goto error; } - kfree(fcall); - fcall = NULL; - result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, - perm, open_mode, &fcall); - if (result < 0) { + err = v9fs_t_create(v9ses, fid, name, perm, mode, &fcall); + if (err < 0) { PRINT_FCALL_ERROR("create fails", fcall); - goto CleanUpFid; + goto error; } - iounit = fcall->params.rcreate.iounit; - qid = fcall->params.rcreate.qid; + if (iounit) + *iounit = fcall->params.rcreate.iounit; + + if (qid) + *qid = fcall->params.rcreate.qid; + + if (fidp) + *fidp = fid; + kfree(fcall); - fcall = NULL; + return 0; - if (!(perm&V9FS_DMDIR)) { - fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); - dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); - if (!fid) { - result = -ENOMEM; - goto CleanUpFid; - } +error: + if (fid >= 0) + v9fs_put_idpool(fid, &v9ses->fidpool); - fid->qid = qid; - fid->iounit = iounit; - } else { - err = v9fs_t_clunk(v9ses, newfid); - newfid = -1; - if (err < 0) - dprintk(DEBUG_ERROR, "clunk for mkdir failed: %d\n", err); - } + kfree(fcall); + return err; +} + +static struct v9fs_fid* +v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) +{ + int err; + u32 nfid; + struct v9fs_fid *ret; + struct v9fs_fcall *fcall; - /* walk to the newly created file and put the fid in the dentry */ - wfidno = v9fs_get_idpool(&v9ses->fidpool); - if (wfidno < 0) { + nfid = v9fs_get_idpool(&v9ses->fidpool); + if (nfid < 0) { eprintk(KERN_WARNING, "no free fids available\n"); - return -ENOSPC; + return ERR_PTR(-ENOSPC); } - result = v9fs_t_walk(v9ses, dirfidnum, wfidno, - (char *) file_dentry->d_name.name, &fcall); - if (result < 0) { - PRINT_FCALL_ERROR("clone error", fcall); - v9fs_put_idpool(wfidno, &v9ses->fidpool); - wfidno = -1; - goto CleanUpFid; + err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, + &fcall); + + if (err < 0) { + PRINT_FCALL_ERROR("walk error", fcall); + v9fs_put_idpool(nfid, &v9ses->fidpool); + goto error; } + kfree(fcall); fcall = NULL; + ret = v9fs_fid_create(v9ses, nfid); + if (!ret) { + err = -ENOMEM; + goto clunk_fid; + } - if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { - v9fs_put_idpool(wfidno, &v9ses->fidpool); - - goto CleanUpFid; + err = v9fs_fid_insert(ret, dentry); + if (err < 0) { + v9fs_fid_destroy(ret); + goto clunk_fid; } - if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) || - (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) || - (perm & V9FS_DMDEVICE)) - return 0; + return ret; - result = v9fs_t_stat(v9ses, wfidno, &fcall); - if (result < 0) { - PRINT_FCALL_ERROR("stat error", fcall); - goto CleanUpFid; - } +clunk_fid: + v9fs_t_clunk(v9ses, nfid); +error: + kfree(fcall); + return ERR_PTR(err); +} + +struct inode * +v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, + struct super_block *sb) +{ + int err, umode; + struct inode *ret; + struct v9fs_fcall *fcall; - file_inode = v9fs_get_inode(sb, - p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode)); + ret = NULL; + err = v9fs_t_stat(v9ses, fid, &fcall); + if (err) { + PRINT_FCALL_ERROR("stat error", fcall); + goto error; + } - if ((!file_inode) || IS_ERR(file_inode)) { - dprintk(DEBUG_ERROR, "create inode failed\n"); - result = -EBADF; - goto CleanUpFid; + umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode); + ret = v9fs_get_inode(sb, umode); + if (IS_ERR(ret)) { + err = PTR_ERR(ret); + ret = NULL; + goto error; } - v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb); + v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb); kfree(fcall); - fcall = NULL; - file_dentry->d_op = &v9fs_dentry_operations; - d_instantiate(file_dentry, file_inode); - - return 0; + return ret; - CleanUpFid: +error: kfree(fcall); - fcall = NULL; + if (ret) + iput(ret); - if (newfid >= 0) { - err = v9fs_t_clunk(v9ses, newfid); - if (err < 0) - dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); - } - if (wfidno >= 0) { - err = v9fs_t_clunk(v9ses, wfidno); - if (err < 0) - dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); - } - return result; + return ERR_PTR(err); } /** @@ -440,20 +434,97 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) return result; } +static int +v9fs_open_created(struct inode *inode, struct file *file) +{ + return 0; +} + /** * v9fs_vfs_create - VFS hook to create files * @inode: directory inode that is being deleted * @dentry: dentry that is being deleted - * @perm: create permissions + * @mode: create permissions * @nd: path information * */ static int -v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm, +v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { - return v9fs_create(inode, dentry, perm, O_RDWR); + int err; + u32 fid, perm, iounit; + int flags; + struct v9fs_session_info *v9ses; + struct v9fs_fid *dfid, *vfid, *ffid; + struct inode *inode; + struct v9fs_qid qid; + struct file *filp; + + inode = NULL; + vfid = NULL; + v9ses = v9fs_inode2v9ses(dir); + dfid = v9fs_fid_lookup(dentry->d_parent); + perm = unixmode2p9mode(v9ses, mode); + + if (nd && nd->flags & LOOKUP_OPEN) + flags = nd->intent.open.flags - 1; + else + flags = O_RDWR; + + err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, + perm, v9fs_uflags2omode(flags), &fid, &qid, &iounit); + + if (err) + goto error; + + vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); + if (IS_ERR(vfid)) { + err = PTR_ERR(vfid); + vfid = NULL; + goto error; + } + + inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + inode = NULL; + goto error; + } + + dentry->d_op = &v9fs_dentry_operations; + d_instantiate(dentry, inode); + + if (nd && nd->flags & LOOKUP_OPEN) { + ffid = v9fs_fid_create(v9ses, fid); + if (!ffid) + return -ENOMEM; + + filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); + if (IS_ERR(filp)) { + v9fs_fid_destroy(ffid); + return PTR_ERR(filp); + } + + ffid->rdir_pos = 0; + ffid->rdir_fcall = NULL; + ffid->fidopen = 1; + ffid->iounit = iounit; + ffid->filp = filp; + filp->private_data = ffid; + } + + return 0; + +error: + if (vfid) + v9fs_fid_destroy(vfid); + + if (inode) + iput(inode); + + return err; } /** @@ -464,9 +535,57 @@ v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm, * */ -static int v9fs_vfs_mkdir(struct inode *inode, struct dentry *dentry, int mode) +static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - return v9fs_create(inode, dentry, mode | S_IFDIR, O_RDONLY); + int err; + u32 fid, perm; + struct v9fs_session_info *v9ses; + struct v9fs_fid *dfid, *vfid; + struct inode *inode; + + inode = NULL; + vfid = NULL; + v9ses = v9fs_inode2v9ses(dir); + dfid = v9fs_fid_lookup(dentry->d_parent); + perm = unixmode2p9mode(v9ses, mode | S_IFDIR); + + err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, + perm, V9FS_OREAD, &fid, NULL, NULL); + + if (err) { + dprintk(DEBUG_ERROR, "create error %d\n", err); + goto error; + } + + err = v9fs_t_clunk(v9ses, fid); + if (err) { + dprintk(DEBUG_ERROR, "clunk error %d\n", err); + goto error; + } + + vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); + if (IS_ERR(vfid)) { + err = PTR_ERR(vfid); + vfid = NULL; + goto error; + } + + inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + inode = NULL; + goto error; + } + + dentry->d_op = &v9fs_dentry_operations; + d_instantiate(dentry, inode); + return 0; + +error: + if (vfid) + v9fs_fid_destroy(vfid); + + return err; } /** @@ -491,10 +610,11 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, int result = 0; dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", - dir, dentry->d_iname, dentry, nameidata); + dir, dentry->d_name.name, dentry, nameidata); sb = dir->i_sb; v9ses = v9fs_inode2v9ses(dir); + dentry->d_op = &v9fs_dentry_operations; dirfid = v9fs_fid_lookup(dentry->d_parent); if (!dirfid) { @@ -516,9 +636,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(-ENOSPC); } - result = - v9fs_t_walk(v9ses, dirfidnum, newfid, (char *)dentry->d_name.name, - NULL); + result = v9fs_t_walk(v9ses, dirfidnum, newfid, + (char *)dentry->d_name.name, NULL); if (result < 0) { v9fs_put_idpool(newfid, &v9ses->fidpool); if (result == -ENOENT) { @@ -551,16 +670,18 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); - fid = v9fs_fid_create(dentry, v9ses, newfid, 0); + fid = v9fs_fid_create(v9ses, newfid); if (fid == NULL) { dprintk(DEBUG_ERROR, "couldn't insert\n"); result = -ENOMEM; goto FreeFcall; } - fid->qid = fcall->params.rstat.stat.qid; + result = v9fs_fid_insert(fid, dentry); + if (result < 0) + goto FreeFcall; - dentry->d_op = &v9fs_dentry_operations; + fid->qid = fcall->params.rstat.stat.qid; v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); d_add(dentry, inode); @@ -886,8 +1007,8 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) } /* copy extension buffer into buffer */ - if (fcall->params.rstat.stat.extension.len+1 < buflen) - buflen = fcall->params.rstat.stat.extension.len + 1; + if (fcall->params.rstat.stat.extension.len < buflen) + buflen = fcall->params.rstat.stat.extension.len; memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); buffer[buflen-1] = 0; @@ -951,7 +1072,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) if (!link) link = ERR_PTR(-ENOMEM); else { - len = v9fs_readlink(dentry, link, PATH_MAX); + len = v9fs_readlink(dentry, link, strlen(link)); if (len < 0) { __putname(link); @@ -983,53 +1104,75 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, int mode, const char *extension) { - int err, retval; + int err; + u32 fid, perm; struct v9fs_session_info *v9ses; + struct v9fs_fid *dfid, *vfid; + struct inode *inode; struct v9fs_fcall *fcall; - struct v9fs_fid *fid; struct v9fs_wstat wstat; - v9ses = v9fs_inode2v9ses(dir); - retval = -EPERM; fcall = NULL; + inode = NULL; + vfid = NULL; + v9ses = v9fs_inode2v9ses(dir); + dfid = v9fs_fid_lookup(dentry->d_parent); + perm = unixmode2p9mode(v9ses, mode); if (!v9ses->extended) { dprintk(DEBUG_ERROR, "not extended\n"); - goto free_mem; + return -EPERM; } - /* issue a create */ - retval = v9fs_create(dir, dentry, mode, 0); - if (retval != 0) - goto free_mem; + err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, + perm, V9FS_OREAD, &fid, NULL, NULL); - fid = v9fs_fid_get_created(dentry); - if (!fid) { - dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); - goto free_mem; + if (err) + goto error; + + err = v9fs_t_clunk(v9ses, fid); + if (err) + goto error; + + vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); + if (IS_ERR(vfid)) { + err = PTR_ERR(vfid); + vfid = NULL; + goto error; + } + + inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + inode = NULL; + goto error; } /* issue a Twstat */ v9fs_blank_wstat(&wstat); wstat.muid = v9ses->name; wstat.extension = (char *) extension; - retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); - if (retval < 0) { - PRINT_FCALL_ERROR("wstat error", fcall); - goto free_mem; - } - - err = v9fs_t_clunk(v9ses, fid->fid); + err = v9fs_t_wstat(v9ses, vfid->fid, &wstat, &fcall); if (err < 0) { - dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); - goto free_mem; + PRINT_FCALL_ERROR("wstat error", fcall); + goto error; } - d_drop(dentry); /* FID - will this also clunk? */ + kfree(fcall); + dentry->d_op = &v9fs_dentry_operations; + d_instantiate(dentry, inode); + return 0; -free_mem: +error: kfree(fcall); - return retval; + if (vfid) + v9fs_fid_destroy(vfid); + + if (inode) + iput(inode); + + return err; + } /** diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 2c4fa75be02..d05318fa684 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -146,7 +146,6 @@ static struct super_block *v9fs_get_sb(struct file_system_type inode->i_gid = gid; root = d_alloc_root(inode); - if (!root) { retval = -ENOMEM; goto put_back_sb; @@ -158,15 +157,20 @@ static struct super_block *v9fs_get_sb(struct file_system_type if (stat_result < 0) { dprintk(DEBUG_ERROR, "stat error\n"); v9fs_t_clunk(v9ses, newfid); - v9fs_put_idpool(newfid, &v9ses->fidpool); } else { /* Setup the Root Inode */ - root_fid = v9fs_fid_create(root, v9ses, newfid, 0); + root_fid = v9fs_fid_create(v9ses, newfid); if (root_fid == NULL) { retval = -ENOMEM; goto put_back_sb; } + retval = v9fs_fid_insert(root_fid, root); + if (retval < 0) { + kfree(fcall); + goto put_back_sb; + } + root_fid->qid = fcall->params.rstat.stat.qid; root->d_inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 2d365cb8eec..dd6048ce053 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -561,7 +561,7 @@ befs_utf2nls(struct super_block *sb, const char *in, * @sb: Superblock * @src: Input string buffer in NLS format * @srclen: Length of input string in bytes - * @dest: The output string in UTF8 format + * @dest: The output string in UTF-8 format * @destlen: Length of the output buffer * * Converts input string @src, which is in the format of the loaded NLS map, diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 1b117a44129..c2eac2a50bd 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -938,6 +938,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) kfree(elf_interpreter); } else { elf_entry = loc->elf_ex.e_entry; + if (BAD_ADDR(elf_entry)) { + send_sig(SIGSEGV, current, 0); + retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + goto out_free_dentry; + } } kfree(elf_phdata); diff --git a/fs/buffer.c b/fs/buffer.c index 62cfd17dc5f..1d3683d496f 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -3051,66 +3051,6 @@ asmlinkage long sys_bdflush(int func, long data) } /* - * Migration function for pages with buffers. This function can only be used - * if the underlying filesystem guarantees that no other references to "page" - * exist. - */ -#ifdef CONFIG_MIGRATION -int buffer_migrate_page(struct page *newpage, struct page *page) -{ - struct address_space *mapping = page->mapping; - struct buffer_head *bh, *head; - - if (!mapping) - return -EAGAIN; - - if (!page_has_buffers(page)) - return migrate_page(newpage, page); - - head = page_buffers(page); - - if (migrate_page_remove_references(newpage, page, 3)) - return -EAGAIN; - - bh = head; - do { - get_bh(bh); - lock_buffer(bh); - bh = bh->b_this_page; - - } while (bh != head); - - ClearPagePrivate(page); - set_page_private(newpage, page_private(page)); - set_page_private(page, 0); - put_page(page); - get_page(newpage); - - bh = head; - do { - set_bh_page(bh, newpage, bh_offset(bh)); - bh = bh->b_this_page; - - } while (bh != head); - - SetPagePrivate(newpage); - - migrate_page_copy(newpage, page); - - bh = head; - do { - unlock_buffer(bh); - put_bh(bh); - bh = bh->b_this_page; - - } while (bh != head); - - return 0; -} -EXPORT_SYMBOL(buffer_migrate_page); -#endif - -/* * Buffer-head allocation */ static kmem_cache_t *bh_cachep; diff --git a/fs/char_dev.c b/fs/char_dev.c index 21195c48163..5c36345c9bf 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -19,6 +19,7 @@ #include <linux/kobject.h> #include <linux/kobj_map.h> #include <linux/cdev.h> +#include <linux/mutex.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> @@ -28,7 +29,7 @@ static struct kobj_map *cdev_map; #define MAX_PROBE_HASH 255 /* random */ -static DECLARE_MUTEX(chrdevs_lock); +static DEFINE_MUTEX(chrdevs_lock); static struct char_device_struct { struct char_device_struct *next; @@ -88,13 +89,13 @@ out: void *acquire_chrdev_list(void) { - down(&chrdevs_lock); + mutex_lock(&chrdevs_lock); return get_next_chrdev(NULL); } void release_chrdev_list(void *dev) { - up(&chrdevs_lock); + mutex_unlock(&chrdevs_lock); kfree(dev); } @@ -151,7 +152,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, memset(cd, 0, sizeof(struct char_device_struct)); - down(&chrdevs_lock); + mutex_lock(&chrdevs_lock); /* temporary */ if (major == 0) { @@ -186,10 +187,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, } cd->next = *cp; *cp = cd; - up(&chrdevs_lock); + mutex_unlock(&chrdevs_lock); return cd; out: - up(&chrdevs_lock); + mutex_unlock(&chrdevs_lock); kfree(cd); return ERR_PTR(ret); } @@ -200,7 +201,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) struct char_device_struct *cd = NULL, **cp; int i = major_to_index(major); - down(&chrdevs_lock); + mutex_lock(&chrdevs_lock); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major == major && (*cp)->baseminor == baseminor && @@ -210,7 +211,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) cd = *cp; *cp = cd->next; } - up(&chrdevs_lock); + mutex_unlock(&chrdevs_lock); return cd; } diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index d335015473a..cb68efba35d 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -160,7 +160,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call. Version 1.25 ------------ Fix internationalization problem in cifs readdir with filenames that map to -longer UTF8 strings than the string on the wire was in Unicode. Add workaround +longer UTF-8 strings than the string on the wire was in Unicode. Add workaround for readdir to netapp servers. Fix search rewind (seek into readdir to return non-consecutive entries). Do not do readdir when server negotiates buffer size to small to fit filename. Add support for reading POSIX ACLs from diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 3c03aadaff0..7b25463d3c1 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -52,7 +52,7 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, int * /* type of buf returned */ , const int long_op); extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); -extern int is_valid_oplock_break(struct smb_hdr *smb); +extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern int is_size_safe_to_change(struct cifsInodeInfo *); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); extern unsigned int smbCalcSize(struct smb_hdr *ptr); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ef5ae6f93c7..2a0c1f4ca0a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -630,7 +630,7 @@ multi_t2_fnd: smallbuf = NULL; } wake_up_process(task_to_wake); - } else if ((is_valid_oplock_break(smb_buffer) == FALSE) + } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) && (isMultiRsp == FALSE)) { cERROR(1, ("No task to wake, unknown frame rcvd!")); cifs_dump_mem("Received Data is: ",(char *)smb_buffer, diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 812c6bb0fe3..432ba15e2c2 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -475,7 +475,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) return 0; } int -is_valid_oplock_break(struct smb_hdr *buf) +is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) { struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; struct list_head *tmp; @@ -535,7 +535,7 @@ is_valid_oplock_break(struct smb_hdr *buf) read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalTreeConnectionList) { tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - if (tcon->tid == buf->Tid) { + if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) { cifs_stats_inc(&tcon->num_oplock_brks); list_for_each(tmp1,&tcon->openFileList){ netfile = list_entry(tmp1,struct cifsFileInfo, diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 057e60217fc..c666769a875 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -446,7 +446,7 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) ifr = ifc.ifc_req; ifr32 = compat_ptr(ifc32.ifcbuf); for (i = 0, j = 0; - i + sizeof (struct ifreq32) < ifc32.ifc_len && j < ifc.ifc_len; + i + sizeof (struct ifreq32) <= ifc32.ifc_len && j < ifc.ifc_len; i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) return -EFAULT; @@ -2531,18 +2531,9 @@ static int rtc_ioctl(unsigned fd, unsigned cmd, unsigned long arg) val32 = kval; return put_user(val32, (unsigned int __user *)arg); case RTC_IRQP_SET32: + return sys_ioctl(fd, RTC_IRQP_SET, arg); case RTC_EPOCH_SET32: - ret = get_user(val32, (unsigned int __user *)arg); - if (ret) - return ret; - kval = val32; - - set_fs(KERNEL_DS); - ret = sys_ioctl(fd, (cmd == RTC_IRQP_SET32) ? - RTC_IRQP_SET : RTC_EPOCH_SET, - (unsigned long)&kval); - set_fs(oldfs); - return ret; + return sys_ioctl(fd, RTC_EPOCH_SET, arg); default: /* unreached */ return -ENOIOCTLCMD; diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 7fe85415ae7..8ad52f5bf25 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -36,7 +36,7 @@ static DECLARE_MUTEX(read_mutex); /* These two macros may change in future, to provide better st_ino semantics. */ -#define CRAMINO(x) ((x)->offset?(x)->offset<<2:1) +#define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1) #define OFFSET(x) ((x)->i_ino) @@ -66,8 +66,36 @@ static int cramfs_iget5_test(struct inode *inode, void *opaque) static int cramfs_iget5_set(struct inode *inode, void *opaque) { + static struct timespec zerotime; struct cramfs_inode *cramfs_inode = opaque; + inode->i_mode = cramfs_inode->mode; + inode->i_uid = cramfs_inode->uid; + inode->i_size = cramfs_inode->size; + inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_gid = cramfs_inode->gid; + /* Struct copy intentional */ + inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; inode->i_ino = CRAMINO(cramfs_inode); + /* inode->i_nlink is left 1 - arguably wrong for directories, + but it's the best we can do without reading the directory + contents. 1 yields the right result in GNU find, even + without -noleaf option. */ + if (S_ISREG(inode->i_mode)) { + inode->i_fop = &generic_ro_fops; + inode->i_data.a_ops = &cramfs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &cramfs_dir_inode_operations; + inode->i_fop = &cramfs_directory_operations; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &page_symlink_inode_operations; + inode->i_data.a_ops = &cramfs_aops; + } else { + inode->i_size = 0; + inode->i_blocks = 0; + init_special_inode(inode, inode->i_mode, + old_decode_dev(cramfs_inode->size)); + } return 0; } @@ -77,37 +105,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode), cramfs_iget5_test, cramfs_iget5_set, cramfs_inode); - static struct timespec zerotime; - if (inode && (inode->i_state & I_NEW)) { - inode->i_mode = cramfs_inode->mode; - inode->i_uid = cramfs_inode->uid; - inode->i_size = cramfs_inode->size; - inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_gid = cramfs_inode->gid; - /* Struct copy intentional */ - inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; - inode->i_ino = CRAMINO(cramfs_inode); - /* inode->i_nlink is left 1 - arguably wrong for directories, - but it's the best we can do without reading the directory - contents. 1 yields the right result in GNU find, even - without -noleaf option. */ - if (S_ISREG(inode->i_mode)) { - inode->i_fop = &generic_ro_fops; - inode->i_data.a_ops = &cramfs_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &cramfs_dir_inode_operations; - inode->i_fop = &cramfs_directory_operations; - } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &page_symlink_inode_operations; - inode->i_data.a_ops = &cramfs_aops; - } else { - inode->i_size = 0; - inode->i_blocks = 0; - init_special_inode(inode, inode->i_mode, - old_decode_dev(cramfs_inode->size)); - } unlock_new_inode(inode); } return inode; diff --git a/fs/dcache.c b/fs/dcache.c index a173bba3266..11dc83092d4 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1736,7 +1736,7 @@ void __init vfs_caches_init(unsigned long mempages) SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, filp_ctor, filp_dtor); + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); dcache_init(mempages); inode_init(mempages); diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index d575452cd9f..40c4fc973fa 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -251,3 +251,49 @@ struct dentry *debugfs_create_bool(const char *name, mode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_bool); +static ssize_t read_file_blob(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct debugfs_blob_wrapper *blob = file->private_data; + return simple_read_from_buffer(user_buf, count, ppos, blob->data, + blob->size); +} + +static struct file_operations fops_blob = { + .read = read_file_blob, + .open = default_open, +}; + +/** + * debugfs_create_blob - create a file in the debugfs filesystem that is + * used to read and write a binary blob. + * + * @name: a pointer to a string containing the name of the file to create. + * @mode: the permission that the file should have + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this paramater is NULL, then the + * file will be created in the root of the debugfs filesystem. + * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer + * to the blob data and the size of the data. + * + * This function creates a file in debugfs with the given name that exports + * @blob->data as a binary blob. If the @mode variable is so set it can be + * read from. Writing is not supported. + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the debugfs_remove() function when the file is + * to be removed (no automatic cleanup happens if your module is unloaded, + * you are responsible here.) If an error occurs, NULL will be returned. + * + * If debugfs is not enabled in the kernel, the value -ENODEV will be + * returned. It is not wise to check for this value, but rather, check for + * NULL or !NULL instead as to eliminate the need for #ifdef in the calling + * code. + */ +struct dentry *debugfs_create_blob(const char *name, mode_t mode, + struct dentry *parent, + struct debugfs_blob_wrapper *blob) +{ + return debugfs_create_file(name, mode, parent, blob, &fops_blob); +} +EXPORT_SYMBOL_GPL(debugfs_create_blob); diff --git a/fs/direct-io.c b/fs/direct-io.c index 848044af7e1..27f3e787fac 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1155,15 +1155,16 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, * For writes, i_mutex is not held on entry; it is never taken. * * DIO_LOCKING (simple locking for regular files) - * For writes we are called under i_mutex and return with i_mutex held, even though - * it is internally dropped. + * For writes we are called under i_mutex and return with i_mutex held, even + * though it is internally dropped. * For reads, i_mutex is not held on entry, but it is taken and dropped before * returning. * * DIO_OWN_LOCKING (filesystem provides synchronisation and handling of * uninitialised data, allowing parallel direct readers and writers) * For writes we are called without i_mutex, return without it, never touch it. - * For reads, i_mutex is held on entry and will be released before returning. + * For reads we are called under i_mutex and return with i_mutex held, even + * though it may be internally dropped. * * Additional i_alloc_sem locking requirements described inline below. */ @@ -1182,7 +1183,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, ssize_t retval = -EINVAL; loff_t end = offset; struct dio *dio; - int reader_with_isem = (rw == READ && dio_lock_type == DIO_OWN_LOCKING); + int release_i_mutex = 0; + int acquire_i_mutex = 0; if (rw & WRITE) current->flags |= PF_SYNCWRITE; @@ -1225,7 +1227,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, * writers need to grab i_alloc_sem only (i_mutex is already held) * For regular files using DIO_OWN_LOCKING, * neither readers nor writers take any locks here - * (i_mutex is already held and release for writers here) */ dio->lock_type = dio_lock_type; if (dio_lock_type != DIO_NO_LOCKING) { @@ -1236,7 +1237,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, mapping = iocb->ki_filp->f_mapping; if (dio_lock_type != DIO_OWN_LOCKING) { mutex_lock(&inode->i_mutex); - reader_with_isem = 1; + release_i_mutex = 1; } retval = filemap_write_and_wait_range(mapping, offset, @@ -1248,7 +1249,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, if (dio_lock_type == DIO_OWN_LOCKING) { mutex_unlock(&inode->i_mutex); - reader_with_isem = 0; + acquire_i_mutex = 1; } } @@ -1269,11 +1270,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, nr_segs, blkbits, get_blocks, end_io, dio); if (rw == READ && dio_lock_type == DIO_LOCKING) - reader_with_isem = 0; + release_i_mutex = 0; out: - if (reader_with_isem) + if (release_i_mutex) mutex_unlock(&inode->i_mutex); + else if (acquire_i_mutex) + mutex_lock(&inode->i_mutex); if (rw & WRITE) current->flags &= ~PF_SYNCWRITE; return retval; diff --git a/fs/exec.c b/fs/exec.c index 0e1c95074d4..0b515ac5313 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -885,6 +885,12 @@ int flush_old_exec(struct linux_binprm * bprm) current->flags &= ~PF_RANDOMIZE; flush_thread(); + /* Set the new mm task size. We have to do that late because it may + * depend on TIF_32BIT which is only updated in flush_thread() on + * some architectures like powerpc + */ + 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)) { diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 7442bdd1267..b3dbd716cd3 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -256,11 +256,10 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) unsigned long npages = dir_pages(inode); unsigned chunk_mask = ~(ext2_chunk_size(inode)-1); unsigned char *types = NULL; - int need_revalidate = (filp->f_version != inode->i_version); - int ret; + int need_revalidate = filp->f_version != inode->i_version; if (pos > inode->i_size - EXT2_DIR_REC_LEN(1)) - goto success; + return 0; if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) types = ext2_filetype_table; @@ -275,12 +274,15 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) "bad page in #%lu", inode->i_ino); filp->f_pos += PAGE_CACHE_SIZE - offset; - ret = -EIO; - goto done; + return -EIO; } kaddr = page_address(page); - if (need_revalidate) { - offset = ext2_validate_entry(kaddr, offset, chunk_mask); + if (unlikely(need_revalidate)) { + if (offset) { + offset = ext2_validate_entry(kaddr, offset, chunk_mask); + filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset; + } + filp->f_version = inode->i_version; need_revalidate = 0; } de = (ext2_dirent *)(kaddr+offset); @@ -289,9 +291,8 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) if (de->rec_len == 0) { ext2_error(sb, __FUNCTION__, "zero-length directory entry"); - ret = -EIO; ext2_put_page(page); - goto done; + return -EIO; } if (de->inode) { int over; @@ -306,19 +307,14 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) le32_to_cpu(de->inode), d_type); if (over) { ext2_put_page(page); - goto success; + return 0; } } filp->f_pos += le16_to_cpu(de->rec_len); } ext2_put_page(page); } - -success: - ret = 0; -done: - filp->f_version = inode->i_version; - return ret; + return 0; } /* diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 3fc4238e970..0384e539b88 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1624,15 +1624,14 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, * For "nobh" option, we can only work if we don't need to * read-in the page - otherwise we create buffers to do the IO. */ - if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH)) { - if (PageUptodate(page)) { - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + offset, 0, length); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - set_page_dirty(page); - goto unlock; - } + if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) && + ext3_should_writeback_data(inode) && PageUptodate(page)) { + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, length); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + set_page_dirty(page); + goto unlock; } if (!page_has_buffers(page)) diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 8bd8ac07770..b8f5cd1e540 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -2141,7 +2141,8 @@ retry: * We have a transaction open. All is sweetness. It also sets * i_size in generic_commit_write(). */ - err = page_symlink(inode, symname, l); + err = __page_symlink(inode, symname, l, + mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); if (err) { ext3_dec_count(handle, inode); ext3_mark_inode_dirty(handle, inode); diff --git a/fs/fat/dir.c b/fs/fat/dir.c index db0de5c621c..4095bc149eb 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -114,7 +114,7 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, } /* - * Convert Unicode 16 to UTF8, translated Unicode, or ASCII. + * Convert Unicode 16 to UTF-8, translated Unicode, or ASCII. * If uni_xlate is enabled and we can't get a 1:1 conversion, use a * colon as an escape character since it is normally invalid on the vfat * filesystem. The following four characters are the hexadecimal digits diff --git a/fs/fat/inode.c b/fs/fat/inode.c index e7f4aa7fc68..e78d7b4842c 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1101,7 +1101,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, return -EINVAL; } } - /* UTF8 doesn't provide FAT semantics */ + /* UTF-8 doesn't provide FAT semantics */ if (!strcmp(opts->iocharset, "utf8")) { printk(KERN_ERR "FAT: utf8 is not a recommended IO charset" " for FAT filesystems, filesystem will be case sensitive!\n"); diff --git a/fs/fifo.c b/fs/fifo.c index 923371b753a..d13fcd3ec80 100644 --- a/fs/fifo.c +++ b/fs/fifo.c @@ -34,10 +34,7 @@ static int fifo_open(struct inode *inode, struct file *filp) { int ret; - ret = -ERESTARTSYS; - if (mutex_lock_interruptible(PIPE_MUTEX(*inode))) - goto err_nolock_nocleanup; - + mutex_lock(PIPE_MUTEX(*inode)); if (!inode->i_pipe) { ret = -ENOMEM; if(!pipe_new(inode)) @@ -140,8 +137,6 @@ err: err_nocleanup: mutex_unlock(PIPE_MUTEX(*inode)); - -err_nolock_nocleanup: return ret; } diff --git a/fs/file_table.c b/fs/file_table.c index 768b5816754..44fabeaa941 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -5,6 +5,7 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include <linux/config.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/file.h> @@ -19,52 +20,67 @@ #include <linux/capability.h> #include <linux/cdev.h> #include <linux/fsnotify.h> +#include <linux/sysctl.h> +#include <linux/percpu_counter.h> + +#include <asm/atomic.h> /* sysctl tunables... */ struct files_stat_struct files_stat = { .max_files = NR_FILE }; -EXPORT_SYMBOL(files_stat); /* Needed by unix.o */ - /* public. Not pretty! */ - __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); +__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); -static DEFINE_SPINLOCK(filp_count_lock); +static struct percpu_counter nr_files __cacheline_aligned_in_smp; -/* slab constructors and destructors are called from arbitrary - * context and must be fully threaded - use a local spinlock - * to protect files_stat.nr_files - */ -void filp_ctor(void *objp, struct kmem_cache *cachep, unsigned long cflags) +static inline void file_free_rcu(struct rcu_head *head) { - if ((cflags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) { - unsigned long flags; - spin_lock_irqsave(&filp_count_lock, flags); - files_stat.nr_files++; - spin_unlock_irqrestore(&filp_count_lock, flags); - } + struct file *f = container_of(head, struct file, f_u.fu_rcuhead); + kmem_cache_free(filp_cachep, f); } -void filp_dtor(void *objp, struct kmem_cache *cachep, unsigned long dflags) +static inline void file_free(struct file *f) { - unsigned long flags; - spin_lock_irqsave(&filp_count_lock, flags); - files_stat.nr_files--; - spin_unlock_irqrestore(&filp_count_lock, flags); + percpu_counter_dec(&nr_files); + call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); } -static inline void file_free_rcu(struct rcu_head *head) +/* + * Return the total number of open files in the system + */ +static int get_nr_files(void) { - struct file *f = container_of(head, struct file, f_u.fu_rcuhead); - kmem_cache_free(filp_cachep, f); + return percpu_counter_read_positive(&nr_files); } -static inline void file_free(struct file *f) +/* + * Return the maximum number of open files in the system + */ +int get_max_files(void) { - call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); + return files_stat.max_files; } +EXPORT_SYMBOL_GPL(get_max_files); + +/* + * Handle nr_files sysctl + */ +#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) +int proc_nr_files(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + files_stat.nr_files = get_nr_files(); + return proc_dointvec(table, write, filp, buffer, lenp, ppos); +} +#else +int proc_nr_files(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + return -ENOSYS; +} +#endif /* Find an unused file structure and return a pointer to it. * Returns NULL, if there are no more free file structures or @@ -78,14 +94,20 @@ struct file *get_empty_filp(void) /* * Privileged users can go above max_files */ - if (files_stat.nr_files >= files_stat.max_files && - !capable(CAP_SYS_ADMIN)) - goto over; + if (get_nr_files() >= files_stat.max_files && !capable(CAP_SYS_ADMIN)) { + /* + * percpu_counters are inaccurate. Do an expensive check before + * we go and fail. + */ + if (percpu_counter_sum(&nr_files) >= files_stat.max_files) + goto over; + } f = kmem_cache_alloc(filp_cachep, GFP_KERNEL); if (f == NULL) goto fail; + percpu_counter_inc(&nr_files); memset(f, 0, sizeof(*f)); if (security_file_alloc(f)) goto fail_sec; @@ -101,10 +123,10 @@ struct file *get_empty_filp(void) over: /* Ran out of filps - report that */ - if (files_stat.nr_files > old_max) { + if (get_nr_files() > old_max) { printk(KERN_INFO "VFS: file-max limit %d reached\n", - files_stat.max_files); - old_max = files_stat.nr_files; + get_max_files()); + old_max = get_nr_files(); } goto fail; @@ -276,4 +298,5 @@ void __init files_init(unsigned long mempages) if (files_stat.max_files < NR_FILE) files_stat.max_files = NR_FILE; files_defer_init(); + percpu_counter_init(&nr_files); } diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 21fd59c7bc2..c72a8a97935 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -111,6 +111,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) /* Doesn't hurt to "reset" the validity timeout */ fuse_invalidate_entry_cache(entry); + + /* For negative dentries, always do a fresh lookup */ if (!inode) return 0; @@ -122,6 +124,9 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); request_send(fc, req); err = req->out.h.error; + /* Zero nodeid is same as -ENOENT */ + if (!err && !outarg.nodeid) + err = -ENOENT; if (!err) { struct fuse_inode *fi = get_fuse_inode(inode); if (outarg.nodeid != get_node_id(inode)) { @@ -190,8 +195,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, fuse_lookup_init(req, dir, entry, &outarg); request_send(fc, req); err = req->out.h.error; - if (!err && ((outarg.nodeid && invalid_nodeid(outarg.nodeid)) || - !valid_mode(outarg.attr.mode))) + /* Zero nodeid is same as -ENOENT, but with valid timeout */ + if (!err && outarg.nodeid && + (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) err = -EIO; if (!err && outarg.nodeid) { inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index b3519528994..25fa8bba8cb 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -56,48 +56,10 @@ static void huge_pagevec_release(struct pagevec *pvec) pagevec_reinit(pvec); } -/* - * huge_pages_needed tries to determine the number of new huge pages that - * will be required to fully populate this VMA. This will be equal to - * the size of the VMA in huge pages minus the number of huge pages - * (covered by this VMA) that are found in the page cache. - * - * Result is in bytes to be compatible with is_hugepage_mem_enough() - */ -static unsigned long -huge_pages_needed(struct address_space *mapping, struct vm_area_struct *vma) -{ - int i; - struct pagevec pvec; - unsigned long start = vma->vm_start; - unsigned long end = vma->vm_end; - unsigned long hugepages = (end - start) >> HPAGE_SHIFT; - pgoff_t next = vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT); - pgoff_t endpg = next + hugepages; - - pagevec_init(&pvec, 0); - while (next < endpg) { - if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) - break; - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; - if (page->index > next) - next = page->index; - if (page->index >= endpg) - break; - next++; - hugepages--; - } - huge_pagevec_release(&pvec); - } - return hugepages << HPAGE_SHIFT; -} - static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) { struct inode *inode = file->f_dentry->d_inode; - struct address_space *mapping = inode->i_mapping; - unsigned long bytes; + struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode); loff_t len, vma_len; int ret; @@ -113,10 +75,6 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) if (vma->vm_end - vma->vm_start < HPAGE_SIZE) return -EINVAL; - bytes = huge_pages_needed(mapping, vma); - if (!is_hugepage_mem_enough(bytes)) - return -ENOMEM; - vma_len = (loff_t)(vma->vm_end - vma->vm_start); mutex_lock(&inode->i_mutex); @@ -129,6 +87,10 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size) goto out; + if (vma->vm_flags & VM_MAYSHARE) + if (hugetlb_extend_reservation(info, len >> HPAGE_SHIFT) != 0) + goto out; + ret = 0; hugetlb_prefault_arch_hook(vma->vm_mm); if (inode->i_size < len) @@ -227,13 +189,18 @@ static void truncate_huge_page(struct page *page) put_page(page); } -static void truncate_hugepages(struct address_space *mapping, loff_t lstart) +static void truncate_hugepages(struct inode *inode, loff_t lstart) { + struct address_space *mapping = &inode->i_data; const pgoff_t start = lstart >> HPAGE_SHIFT; struct pagevec pvec; pgoff_t next; int i; + hugetlb_truncate_reservation(HUGETLBFS_I(inode), + lstart >> HPAGE_SHIFT); + if (!mapping->nrpages) + return; pagevec_init(&pvec, 0); next = start; while (1) { @@ -262,8 +229,7 @@ static void truncate_hugepages(struct address_space *mapping, loff_t lstart) static void hugetlbfs_delete_inode(struct inode *inode) { - if (inode->i_data.nrpages) - truncate_hugepages(&inode->i_data, 0); + truncate_hugepages(inode, 0); clear_inode(inode); } @@ -296,8 +262,7 @@ static void hugetlbfs_forget_inode(struct inode *inode) inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); - if (inode->i_data.nrpages) - truncate_hugepages(&inode->i_data, 0); + truncate_hugepages(inode, 0); clear_inode(inode); destroy_inode(inode); } @@ -356,7 +321,7 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) if (!prio_tree_empty(&mapping->i_mmap)) hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); spin_unlock(&mapping->i_mmap_lock); - truncate_hugepages(mapping, offset); + truncate_hugepages(inode, offset); return 0; } @@ -573,6 +538,7 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb) hugetlbfs_inc_free_inodes(sbinfo); return NULL; } + p->prereserved_hpages = 0; return &p->vfs_inode; } @@ -771,21 +737,6 @@ static struct file_system_type hugetlbfs_fs_type = { static struct vfsmount *hugetlbfs_vfsmount; -/* - * Return the next identifier for a shm file - */ -static unsigned long hugetlbfs_counter(void) -{ - static DEFINE_SPINLOCK(lock); - static unsigned long counter; - unsigned long ret; - - spin_lock(&lock); - ret = ++counter; - spin_unlock(&lock); - return ret; -} - static int can_do_hugetlb_shm(void) { return likely(capable(CAP_IPC_LOCK) || @@ -801,18 +752,16 @@ struct file *hugetlb_zero_setup(size_t size) struct dentry *dentry, *root; struct qstr quick_string; char buf[16]; + static atomic_t counter; if (!can_do_hugetlb_shm()) return ERR_PTR(-EPERM); - if (!is_hugepage_mem_enough(size)) - return ERR_PTR(-ENOMEM); - if (!user_shm_lock(size, current->user)) return ERR_PTR(-ENOMEM); root = hugetlbfs_vfsmount->mnt_root; - snprintf(buf, 16, "%lu", hugetlbfs_counter()); + snprintf(buf, 16, "%u", atomic_inc_return(&counter)); quick_string.name = buf; quick_string.len = strlen(quick_string.name); quick_string.hash = 0; @@ -831,6 +780,11 @@ struct file *hugetlb_zero_setup(size_t size) if (!inode) goto out_file; + error = -ENOMEM; + if (hugetlb_extend_reservation(HUGETLBFS_I(inode), + size >> HPAGE_SHIFT) != 0) + goto out_inode; + d_instantiate(dentry, inode); inode->i_size = size; inode->i_nlink = 0; @@ -841,6 +795,8 @@ struct file *hugetlb_zero_setup(size_t size) file->f_mode = FMODE_WRITE | FMODE_READ; return file; +out_inode: + iput(inode); out_file: put_filp(file); out_dentry: diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c index 2931de7f1a6..81a90e170ac 100644 --- a/fs/isofs/joliet.c +++ b/fs/isofs/joliet.c @@ -11,7 +11,7 @@ #include "isofs.h" /* - * Convert Unicode 16 to UTF8 or ASCII. + * Convert Unicode 16 to UTF-8 or ASCII. */ static int uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls) diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index b635e167a3f..d4d0c41490c 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -406,7 +406,8 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info int err = 0, pointed = 0; struct jffs2_eraseblock *jeb; unsigned char *buffer; - uint32_t crc, ofs, retlen, len; + uint32_t crc, ofs, len; + size_t retlen; BUG_ON(tn->csize == 0); diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 5f0652df5d4..f1695642d0f 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -112,7 +112,7 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r * negative error code on failure. */ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, - struct jffs2_raw_dirent *rd, uint32_t read, struct jffs2_full_dirent **fdp, + struct jffs2_raw_dirent *rd, size_t read, struct jffs2_full_dirent **fdp, uint32_t *latest_mctime, uint32_t *mctime_ver) { struct jffs2_full_dirent *fd; diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 3e51dd1da8a..cf55b221fc2 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -233,7 +233,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) c->nextblock->dirty_size = 0; } #ifdef CONFIG_JFFS2_FS_WRITEBUFFER - if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size % c->wbuf_pagesize)) { + if (!jffs2_can_mark_obsolete(c) && c->wbuf_pagesize && c->nextblock && (c->nextblock->free_size % c->wbuf_pagesize)) { /* If we're going to start writing into a block which already contains data, and the end of the data isn't page-aligned, skip a little and align it. */ diff --git a/fs/jfs/Makefile b/fs/jfs/Makefile index 6f1e0e95587..3adb6395e42 100644 --- a/fs/jfs/Makefile +++ b/fs/jfs/Makefile @@ -8,7 +8,8 @@ jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ jfs_unicode.o jfs_dtree.o jfs_inode.o \ jfs_extent.o symlink.o jfs_metapage.o \ - jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o resize.o xattr.o + jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \ + resize.o xattr.o ioctl.o jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 461e4934ca7..e2281300979 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -183,6 +183,9 @@ cleanup: posix_acl_release(acl); } else inode->i_mode &= ~current->fs->umask; + + JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | + inode->i_mode; return rc; } @@ -207,12 +210,12 @@ static int jfs_acl_chmod(struct inode *inode) rc = posix_acl_chmod_masq(clone, inode->i_mode); if (!rc) { tid_t tid = txBegin(inode->i_sb, 0); - down(&JFS_IP(inode)->commit_sem); + mutex_lock(&JFS_IP(inode)->commit_mutex); rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); - up(&JFS_IP(inode)->commit_sem); + mutex_unlock(&JFS_IP(inode)->commit_mutex); } posix_acl_release(clone); diff --git a/fs/jfs/file.c b/fs/jfs/file.c index c2c19c9ed9a..e1ac6e497e2 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -113,4 +113,5 @@ struct file_operations jfs_file_operations = { .sendfile = generic_file_sendfile, .fsync = jfs_fsync, .release = jfs_release, + .ioctl = jfs_ioctl, }; diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 9f942ca8e4e..51a5fed90cc 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -55,6 +55,7 @@ void jfs_read_inode(struct inode *inode) inode->i_op = &jfs_file_inode_operations; init_special_inode(inode, inode->i_mode, inode->i_rdev); } + jfs_set_inode_flags(inode); } /* @@ -89,16 +90,16 @@ int jfs_commit_inode(struct inode *inode, int wait) } tid = txBegin(inode->i_sb, COMMIT_INODE); - down(&JFS_IP(inode)->commit_sem); + mutex_lock(&JFS_IP(inode)->commit_mutex); /* - * Retest inode state after taking commit_sem + * Retest inode state after taking commit_mutex */ if (inode->i_nlink && test_cflag(COMMIT_Dirty, inode)) rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0); txEnd(tid); - up(&JFS_IP(inode)->commit_sem); + mutex_unlock(&JFS_IP(inode)->commit_mutex); return rc; } @@ -335,18 +336,18 @@ void jfs_truncate_nolock(struct inode *ip, loff_t length) tid = txBegin(ip->i_sb, 0); /* - * The commit_sem cannot be taken before txBegin. + * The commit_mutex cannot be taken before txBegin. * txBegin may block and there is a chance the inode * could be marked dirty and need to be committed * before txBegin unblocks */ - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); newsize = xtTruncate(tid, ip, length, COMMIT_TRUNCATE | COMMIT_PWMAP); if (newsize < 0) { txEnd(tid); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); break; } @@ -355,7 +356,7 @@ void jfs_truncate_nolock(struct inode *ip, loff_t length) txCommit(tid, 1, &ip, 0); txEnd(tid); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); } while (newsize > length); /* Truncate isn't always atomic */ } diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c new file mode 100644 index 00000000000..67b3774820e --- /dev/null +++ b/fs/jfs/ioctl.c @@ -0,0 +1,107 @@ +/* + * linux/fs/jfs/ioctl.c + * + * Copyright (C) 2006 Herbert Poetzl + * adapted from Remy Card's ext2/ioctl.c + */ + +#include <linux/fs.h> +#include <linux/ext2_fs.h> +#include <linux/ctype.h> +#include <linux/capability.h> +#include <linux/time.h> +#include <asm/current.h> +#include <asm/uaccess.h> + +#include "jfs_incore.h" +#include "jfs_dinode.h" +#include "jfs_inode.h" + + +static struct { + long jfs_flag; + long ext2_flag; +} jfs_map[] = { + {JFS_NOATIME_FL, EXT2_NOATIME_FL}, + {JFS_DIRSYNC_FL, EXT2_DIRSYNC_FL}, + {JFS_SYNC_FL, EXT2_SYNC_FL}, + {JFS_SECRM_FL, EXT2_SECRM_FL}, + {JFS_UNRM_FL, EXT2_UNRM_FL}, + {JFS_APPEND_FL, EXT2_APPEND_FL}, + {JFS_IMMUTABLE_FL, EXT2_IMMUTABLE_FL}, + {0, 0}, +}; + +static long jfs_map_ext2(unsigned long flags, int from) +{ + int index=0; + long mapped=0; + + while (jfs_map[index].jfs_flag) { + if (from) { + if (jfs_map[index].ext2_flag & flags) + mapped |= jfs_map[index].jfs_flag; + } else { + if (jfs_map[index].jfs_flag & flags) + mapped |= jfs_map[index].ext2_flag; + } + index++; + } + return mapped; +} + + +int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, + unsigned long arg) +{ + struct jfs_inode_info *jfs_inode = JFS_IP(inode); + unsigned int flags; + + switch (cmd) { + case JFS_IOC_GETFLAGS: + flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE; + flags = jfs_map_ext2(flags, 0); + return put_user(flags, (int __user *) arg); + case JFS_IOC_SETFLAGS: { + unsigned int oldflags; + + if (IS_RDONLY(inode)) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(flags, (int __user *) arg)) + return -EFAULT; + + flags = jfs_map_ext2(flags, 1); + if (!S_ISDIR(inode->i_mode)) + flags &= ~JFS_DIRSYNC_FL; + + oldflags = jfs_inode->mode2; + + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the relevant capability. + */ + if ((oldflags & JFS_IMMUTABLE_FL) || + ((flags ^ oldflags) & + (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) { + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + } + + flags = flags & JFS_FL_USER_MODIFIABLE; + flags |= oldflags & ~JFS_FL_USER_MODIFIABLE; + jfs_inode->mode2 = flags; + + jfs_set_inode_flags(inode); + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); + return 0; + } + default: + return -ENOTTY; + } +} + diff --git a/fs/jfs/jfs_dinode.h b/fs/jfs/jfs_dinode.h index 580a3258449..9f2572aea56 100644 --- a/fs/jfs/jfs_dinode.h +++ b/fs/jfs/jfs_dinode.h @@ -139,13 +139,36 @@ struct dinode { /* more extended mode bits: attributes for OS/2 */ #define IREADONLY 0x02000000 /* no write access to file */ -#define IARCHIVE 0x40000000 /* file archive bit */ -#define ISYSTEM 0x08000000 /* system file */ #define IHIDDEN 0x04000000 /* hidden file */ -#define IRASH 0x4E000000 /* mask for changeable attributes */ -#define INEWNAME 0x80000000 /* non-8.3 filename format */ +#define ISYSTEM 0x08000000 /* system file */ + #define IDIRECTORY 0x20000000 /* directory (shadow of real bit) */ +#define IARCHIVE 0x40000000 /* file archive bit */ +#define INEWNAME 0x80000000 /* non-8.3 filename format */ + +#define IRASH 0x4E000000 /* mask for changeable attributes */ #define ATTRSHIFT 25 /* bits to shift to move attribute specification to mode position */ +/* extended attributes for Linux */ + +#define JFS_NOATIME_FL 0x00080000 /* do not update atime */ + +#define JFS_DIRSYNC_FL 0x00100000 /* dirsync behaviour */ +#define JFS_SYNC_FL 0x00200000 /* Synchronous updates */ +#define JFS_SECRM_FL 0x00400000 /* Secure deletion */ +#define JFS_UNRM_FL 0x00800000 /* allow for undelete */ + +#define JFS_APPEND_FL 0x01000000 /* writes to file may only append */ +#define JFS_IMMUTABLE_FL 0x02000000 /* Immutable file */ + +#define JFS_FL_USER_VISIBLE 0x03F80000 +#define JFS_FL_USER_MODIFIABLE 0x03F80000 +#define JFS_FL_INHERIT 0x03C80000 + +/* These are identical to EXT[23]_IOC_GETFLAGS/SETFLAGS */ +#define JFS_IOC_GETFLAGS _IOR('f', 1, long) +#define JFS_IOC_SETFLAGS _IOW('f', 2, long) + + #endif /*_H_JFS_DINODE */ diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 2967b739341..c161c98954e 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -64,9 +64,9 @@ * to the persistent bitmaps in dmaps) is guarded by (busy) buffers. */ -#define BMAP_LOCK_INIT(bmp) init_MUTEX(&bmp->db_bmaplock) -#define BMAP_LOCK(bmp) down(&bmp->db_bmaplock) -#define BMAP_UNLOCK(bmp) up(&bmp->db_bmaplock) +#define BMAP_LOCK_INIT(bmp) mutex_init(&bmp->db_bmaplock) +#define BMAP_LOCK(bmp) mutex_lock(&bmp->db_bmaplock) +#define BMAP_UNLOCK(bmp) mutex_unlock(&bmp->db_bmaplock) /* * forward references @@ -125,7 +125,7 @@ static int dbGetL2AGSize(s64 nblocks); * into the table, with the table elements yielding the maximum * binary buddy of free bits within the character. */ -static s8 budtab[256] = { +static const s8 budtab[256] = { 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -532,10 +532,10 @@ dbUpdatePMap(struct inode *ipbmap, lastlblkno = lblkno; + LOGSYNC_LOCK(log, flags); if (mp->lsn != 0) { /* inherit older/smaller lsn */ logdiff(diffp, mp->lsn, log); - LOGSYNC_LOCK(log, flags); if (difft < diffp) { mp->lsn = lsn; @@ -548,20 +548,17 @@ dbUpdatePMap(struct inode *ipbmap, logdiff(diffp, mp->clsn, log); if (difft > diffp) mp->clsn = tblk->clsn; - LOGSYNC_UNLOCK(log, flags); } else { mp->log = log; mp->lsn = lsn; /* insert bp after tblock in logsync list */ - LOGSYNC_LOCK(log, flags); - log->count++; list_add(&mp->synclist, &tblk->synclist); mp->clsn = tblk->clsn; - LOGSYNC_UNLOCK(log, flags); } + LOGSYNC_UNLOCK(log, flags); } /* write the last buffer. */ diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h index 32e25884e7e..8b14cc8e022 100644 --- a/fs/jfs/jfs_dmap.h +++ b/fs/jfs/jfs_dmap.h @@ -243,7 +243,7 @@ struct dbmap { struct bmap { struct dbmap db_bmap; /* on-disk aggregate map descriptor */ struct inode *db_ipbmap; /* ptr to aggregate map incore inode */ - struct semaphore db_bmaplock; /* aggregate map lock */ + struct mutex db_bmaplock; /* aggregate map lock */ atomic_t db_active[MAXAG]; /* count of active, open files in AG */ u32 *db_DBmap; }; diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 404f33eae50..6c3f0831984 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -1005,6 +1005,9 @@ static int dtSplitUp(tid_t tid, DT_PUTPAGE(smp); + if (!DO_INDEX(ip)) + ip->i_size = xlen << sbi->l2bsize; + goto freeKeyName; } @@ -1055,7 +1058,9 @@ static int dtSplitUp(tid_t tid, xaddr = addressPXD(pxd) + xlen; dbFree(ip, xaddr, (s64) n); } - } + } else if (!DO_INDEX(ip)) + ip->i_size = lengthPXD(pxd) << sbi->l2bsize; + extendOut: DT_PUTPAGE(smp); @@ -1098,6 +1103,9 @@ static int dtSplitUp(tid_t tid, goto splitOut; } + if (!DO_INDEX(ip)) + ip->i_size += PSIZE; + /* * propagate up the router entry for the leaf page just split * @@ -2424,6 +2432,9 @@ static int dtDeleteUp(tid_t tid, struct inode *ip, break; } + if (!DO_INDEX(ip)) + ip->i_size -= PSIZE; + return 0; } diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 4879603daa1..5549378358b 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -94,7 +94,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) txBeginAnon(ip->i_sb); /* Avoid race with jfs_commit_inode() */ - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* validate extent length */ if (xlen > MAXXLEN) @@ -136,14 +136,14 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) */ nxlen = xlen; if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) { - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); } /* Allocate blocks to quota. */ if (DQUOT_ALLOC_BLOCK(ip, nxlen)) { dbFree(ip, nxaddr, (s64) nxlen); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; } @@ -165,7 +165,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) if (rc) { dbFree(ip, nxaddr, nxlen); DQUOT_FREE_BLOCK(ip, nxlen); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); } @@ -177,7 +177,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) mark_inode_dirty(ip); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); /* * COMMIT_SyncList flags an anonymous tlock on page that is on * sync list. @@ -222,7 +222,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr) /* This blocks if we are low on resources */ txBeginAnon(ip->i_sb); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* validate extent length */ if (nxlen > MAXXLEN) nxlen = MAXXLEN; @@ -258,7 +258,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr) /* Allocat blocks to quota. */ if (DQUOT_ALLOC_BLOCK(ip, nxlen)) { dbFree(ip, nxaddr, (s64) nxlen); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; } @@ -338,7 +338,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr) mark_inode_dirty(ip); exit: - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); } #endif /* _NOTYET */ @@ -439,12 +439,12 @@ int extRecord(struct inode *ip, xad_t * xp) txBeginAnon(ip->i_sb); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* update the extent */ rc = xtUpdate(0, ip, xp); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return rc; } diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 31b4aa13dd4..ccbe60aff83 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -66,14 +66,14 @@ static HLIST_HEAD(aggregate_hash); * imap locks */ /* iag free list lock */ -#define IAGFREE_LOCK_INIT(imap) init_MUTEX(&imap->im_freelock) -#define IAGFREE_LOCK(imap) down(&imap->im_freelock) -#define IAGFREE_UNLOCK(imap) up(&imap->im_freelock) +#define IAGFREE_LOCK_INIT(imap) mutex_init(&imap->im_freelock) +#define IAGFREE_LOCK(imap) mutex_lock(&imap->im_freelock) +#define IAGFREE_UNLOCK(imap) mutex_unlock(&imap->im_freelock) /* per ag iag list locks */ -#define AG_LOCK_INIT(imap,index) init_MUTEX(&(imap->im_aglock[index])) -#define AG_LOCK(imap,agno) down(&imap->im_aglock[agno]) -#define AG_UNLOCK(imap,agno) up(&imap->im_aglock[agno]) +#define AG_LOCK_INIT(imap,index) mutex_init(&(imap->im_aglock[index])) +#define AG_LOCK(imap,agno) mutex_lock(&imap->im_aglock[agno]) +#define AG_UNLOCK(imap,agno) mutex_unlock(&imap->im_aglock[agno]) /* * forward references @@ -1261,7 +1261,7 @@ int diFree(struct inode *ip) * to be freed by the transaction; */ tid = txBegin(ipimap->i_sb, COMMIT_FORCE); - down(&JFS_IP(ipimap)->commit_sem); + mutex_lock(&JFS_IP(ipimap)->commit_mutex); /* acquire tlock of the iag page of the freed ixad * to force the page NOHOMEOK (even though no data is @@ -1294,7 +1294,7 @@ int diFree(struct inode *ip) rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); txEnd(tid); - up(&JFS_IP(ipimap)->commit_sem); + mutex_unlock(&JFS_IP(ipimap)->commit_mutex); /* unlock the AG inode map information */ AG_UNLOCK(imap, agno); @@ -2554,13 +2554,13 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) * addressing structure pointing to the new iag page; */ tid = txBegin(sb, COMMIT_FORCE); - down(&JFS_IP(ipimap)->commit_sem); + mutex_lock(&JFS_IP(ipimap)->commit_mutex); /* update the inode map addressing structure to point to it */ if ((rc = xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) { txEnd(tid); - up(&JFS_IP(ipimap)->commit_sem); + mutex_unlock(&JFS_IP(ipimap)->commit_mutex); /* Free the blocks allocated for the iag since it was * not successfully added to the inode map */ @@ -2626,7 +2626,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); txEnd(tid); - up(&JFS_IP(ipimap)->commit_sem); + mutex_unlock(&JFS_IP(ipimap)->commit_mutex); duplicateIXtree(sb, blkno, xlen, &xaddr); @@ -2844,11 +2844,11 @@ diUpdatePMap(struct inode *ipimap, */ lsn = tblk->lsn; log = JFS_SBI(tblk->sb)->log; + LOGSYNC_LOCK(log, flags); if (mp->lsn != 0) { /* inherit older/smaller lsn */ logdiff(difft, lsn, log); logdiff(diffp, mp->lsn, log); - LOGSYNC_LOCK(log, flags); if (difft < diffp) { mp->lsn = lsn; /* move mp after tblock in logsync list */ @@ -2860,17 +2860,15 @@ diUpdatePMap(struct inode *ipimap, logdiff(diffp, mp->clsn, log); if (difft > diffp) mp->clsn = tblk->clsn; - LOGSYNC_UNLOCK(log, flags); } else { mp->log = log; mp->lsn = lsn; /* insert mp after tblock in logsync list */ - LOGSYNC_LOCK(log, flags); log->count++; list_add(&mp->synclist, &tblk->synclist); mp->clsn = tblk->clsn; - LOGSYNC_UNLOCK(log, flags); } + LOGSYNC_UNLOCK(log, flags); write_metapage(mp); return (0); } @@ -3076,14 +3074,40 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno, static int copy_from_dinode(struct dinode * dip, struct inode *ip) { struct jfs_inode_info *jfs_ip = JFS_IP(ip); + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); jfs_ip->fileset = le32_to_cpu(dip->di_fileset); jfs_ip->mode2 = le32_to_cpu(dip->di_mode); ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff; + if (sbi->umask != -1) { + ip->i_mode = (ip->i_mode & ~0777) | (0777 & ~sbi->umask); + /* For directories, add x permission if r is allowed by umask */ + if (S_ISDIR(ip->i_mode)) { + if (ip->i_mode & 0400) + ip->i_mode |= 0100; + if (ip->i_mode & 0040) + ip->i_mode |= 0010; + if (ip->i_mode & 0004) + ip->i_mode |= 0001; + } + } ip->i_nlink = le32_to_cpu(dip->di_nlink); - ip->i_uid = le32_to_cpu(dip->di_uid); - ip->i_gid = le32_to_cpu(dip->di_gid); + + jfs_ip->saved_uid = le32_to_cpu(dip->di_uid); + if (sbi->uid == -1) + ip->i_uid = jfs_ip->saved_uid; + else { + ip->i_uid = sbi->uid; + } + + jfs_ip->saved_gid = le32_to_cpu(dip->di_gid); + if (sbi->gid == -1) + ip->i_gid = jfs_ip->saved_gid; + else { + ip->i_gid = sbi->gid; + } + ip->i_size = le64_to_cpu(dip->di_size); ip->i_atime.tv_sec = le32_to_cpu(dip->di_atime.tv_sec); ip->i_atime.tv_nsec = le32_to_cpu(dip->di_atime.tv_nsec); @@ -3134,21 +3158,33 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) static void copy_to_dinode(struct dinode * dip, struct inode *ip) { struct jfs_inode_info *jfs_ip = JFS_IP(ip); + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); dip->di_fileset = cpu_to_le32(jfs_ip->fileset); - dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp); + dip->di_inostamp = cpu_to_le32(sbi->inostamp); dip->di_number = cpu_to_le32(ip->i_ino); dip->di_gen = cpu_to_le32(ip->i_generation); dip->di_size = cpu_to_le64(ip->i_size); dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks)); dip->di_nlink = cpu_to_le32(ip->i_nlink); - dip->di_uid = cpu_to_le32(ip->i_uid); - dip->di_gid = cpu_to_le32(ip->i_gid); + if (sbi->uid == -1) + dip->di_uid = cpu_to_le32(ip->i_uid); + else + dip->di_uid = cpu_to_le32(jfs_ip->saved_uid); + if (sbi->gid == -1) + dip->di_gid = cpu_to_le32(ip->i_gid); + else + dip->di_gid = cpu_to_le32(jfs_ip->saved_gid); /* * mode2 is only needed for storing the higher order bits. * Trust i_mode for the lower order ones */ - dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | ip->i_mode); + if (sbi->umask == -1) + dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | + ip->i_mode); + else /* Leave the original permissions alone */ + dip->di_mode = cpu_to_le32(jfs_ip->mode2); + dip->di_atime.tv_sec = cpu_to_le32(ip->i_atime.tv_sec); dip->di_atime.tv_nsec = cpu_to_le32(ip->i_atime.tv_nsec); dip->di_ctime.tv_sec = cpu_to_le32(ip->i_ctime.tv_sec); diff --git a/fs/jfs/jfs_imap.h b/fs/jfs/jfs_imap.h index 6b59adec036..6e24465f0f9 100644 --- a/fs/jfs/jfs_imap.h +++ b/fs/jfs/jfs_imap.h @@ -140,8 +140,8 @@ struct dinomap { struct inomap { struct dinomap im_imap; /* 4096: inode allocation control */ struct inode *im_ipimap; /* 4: ptr to inode for imap */ - struct semaphore im_freelock; /* 4: iag free list lock */ - struct semaphore im_aglock[MAXAG]; /* 512: per AG locks */ + struct mutex im_freelock; /* 4: iag free list lock */ + struct mutex im_aglock[MAXAG]; /* 512: per AG locks */ u32 *im_DBGdimap; atomic_t im_numinos; /* num of backed inodes */ atomic_t im_numfree; /* num of free backed inodes */ diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index dc21a5bd54d..54d73716ca8 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h @@ -19,6 +19,7 @@ #ifndef _H_JFS_INCORE #define _H_JFS_INCORE +#include <linux/mutex.h> #include <linux/rwsem.h> #include <linux/slab.h> #include <linux/bitops.h> @@ -37,6 +38,8 @@ struct jfs_inode_info { int fileset; /* fileset number (always 16)*/ uint mode2; /* jfs-specific mode */ + uint saved_uid; /* saved for uid mount option */ + uint saved_gid; /* saved for gid mount option */ pxd_t ixpxd; /* inode extent descriptor */ dxd_t acl; /* dxd describing acl */ dxd_t ea; /* dxd describing ea */ @@ -62,12 +65,12 @@ struct jfs_inode_info { */ struct rw_semaphore rdwrlock; /* - * commit_sem serializes transaction processing on an inode. + * commit_mutex serializes transaction processing on an inode. * It must be taken after beginning a transaction (txBegin), since * dirty inodes may be committed while a new transaction on the * inode is blocked in txBegin or TxBeginAnon */ - struct semaphore commit_sem; + struct mutex commit_mutex; /* xattr_sem allows us to access the xattrs without taking i_mutex */ struct rw_semaphore xattr_sem; lid_t xtlid; /* lid of xtree lock on directory */ @@ -169,6 +172,9 @@ struct jfs_sb_info { uint state; /* mount/recovery state */ unsigned long flag; /* mount time flags */ uint p_state; /* state prior to going no integrity */ + uint uid; /* uid to override on-disk uid */ + uint gid; /* gid to override on-disk gid */ + uint umask; /* umask to override on-disk umask */ }; /* jfs_sb_info commit_state */ diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c index 2af5efbfd06..495df402916 100644 --- a/fs/jfs/jfs_inode.c +++ b/fs/jfs/jfs_inode.c @@ -25,6 +25,26 @@ #include "jfs_dinode.h" #include "jfs_debug.h" + +void jfs_set_inode_flags(struct inode *inode) +{ + unsigned int flags = JFS_IP(inode)->mode2; + + inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | + S_NOATIME | S_DIRSYNC | S_SYNC); + + if (flags & JFS_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & JFS_APPEND_FL) + inode->i_flags |= S_APPEND; + if (flags & JFS_NOATIME_FL) + inode->i_flags |= S_NOATIME; + if (flags & JFS_DIRSYNC_FL) + inode->i_flags |= S_DIRSYNC; + if (flags & JFS_SYNC_FL) + inode->i_flags |= S_SYNC; +} + /* * NAME: ialloc() * @@ -63,6 +83,13 @@ struct inode *ialloc(struct inode *parent, umode_t mode) inode->i_gid = current->fsgid; /* + * New inodes need to save sane values on disk when + * uid & gid mount options are used + */ + jfs_inode->saved_uid = inode->i_uid; + jfs_inode->saved_gid = inode->i_gid; + + /* * Allocate inode to quota. */ if (DQUOT_ALLOC_INODE(inode)) { @@ -74,10 +101,20 @@ struct inode *ialloc(struct inode *parent, umode_t mode) } inode->i_mode = mode; - if (S_ISDIR(mode)) - jfs_inode->mode2 = IDIRECTORY | mode; - else - jfs_inode->mode2 = INLINEEA | ISPARSE | mode; + /* inherit flags from parent */ + jfs_inode->mode2 = JFS_IP(parent)->mode2 & JFS_FL_INHERIT; + + if (S_ISDIR(mode)) { + jfs_inode->mode2 |= IDIRECTORY; + jfs_inode->mode2 &= ~JFS_DIRSYNC_FL; + } + else { + jfs_inode->mode2 |= INLINEEA | ISPARSE; + if (S_ISLNK(mode)) + jfs_inode->mode2 &= ~(JFS_IMMUTABLE_FL|JFS_APPEND_FL); + } + jfs_inode->mode2 |= mode; + inode->i_blksize = sb->s_blocksize; inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; @@ -98,6 +135,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode) jfs_inode->atlhead = 0; jfs_inode->atltail = 0; jfs_inode->xtlid = 0; + jfs_set_inode_flags(inode); jfs_info("ialloc returns inode = 0x%p\n", inode); diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index b54bac576cb..095d471b9f9 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h @@ -20,6 +20,8 @@ extern struct inode *ialloc(struct inode *, umode_t); extern int jfs_fsync(struct file *, struct dentry *, int); +extern int jfs_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); extern void jfs_read_inode(struct inode *); extern int jfs_commit_inode(struct inode *, int); extern int jfs_write_inode(struct inode*, int); @@ -29,6 +31,7 @@ extern void jfs_truncate(struct inode *); extern void jfs_truncate_nolock(struct inode *, loff_t); extern void jfs_free_zero_link(struct inode *); extern struct dentry *jfs_get_parent(struct dentry *dentry); +extern void jfs_set_inode_flags(struct inode *); extern struct address_space_operations jfs_aops; extern struct inode_operations jfs_dir_inode_operations; diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h index 10ad1d08668..70ac9f7d1e0 100644 --- a/fs/jfs/jfs_lock.h +++ b/fs/jfs/jfs_lock.h @@ -20,6 +20,7 @@ #define _H_JFS_LOCK #include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/sched.h> /* diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index d27bac6acaa..0b348b13b55 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -64,6 +64,7 @@ #include <linux/interrupt.h> #include <linux/smp_lock.h> #include <linux/completion.h> +#include <linux/kthread.h> #include <linux/buffer_head.h> /* for sync_blockdev() */ #include <linux/bio.h> #include <linux/suspend.h> @@ -81,15 +82,14 @@ */ static struct lbuf *log_redrive_list; static DEFINE_SPINLOCK(log_redrive_lock); -DECLARE_WAIT_QUEUE_HEAD(jfs_IO_thread_wait); /* * log read/write serialization (per log) */ -#define LOG_LOCK_INIT(log) init_MUTEX(&(log)->loglock) -#define LOG_LOCK(log) down(&((log)->loglock)) -#define LOG_UNLOCK(log) up(&((log)->loglock)) +#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) /* @@ -1105,11 +1105,10 @@ int lmLogOpen(struct super_block *sb) } } - if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL))) { + if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) { up(&jfs_log_sem); return -ENOMEM; } - memset(log, 0, sizeof(struct jfs_log)); INIT_LIST_HEAD(&log->sb_list); init_waitqueue_head(&log->syncwait); @@ -1181,9 +1180,8 @@ static int open_inline_log(struct super_block *sb) struct jfs_log *log; int rc; - if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL))) + if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) return -ENOMEM; - memset(log, 0, sizeof(struct jfs_log)); INIT_LIST_HEAD(&log->sb_list); init_waitqueue_head(&log->syncwait); @@ -1216,12 +1214,11 @@ static int open_dummy_log(struct super_block *sb) down(&jfs_log_sem); if (!dummy_log) { - dummy_log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL); + dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL); if (!dummy_log) { up(&jfs_log_sem); return -ENOMEM; } - memset(dummy_log, 0, sizeof(struct jfs_log)); INIT_LIST_HEAD(&dummy_log->sb_list); init_waitqueue_head(&dummy_log->syncwait); dummy_log->no_integrity = 1; @@ -1980,7 +1977,7 @@ static inline void lbmRedrive(struct lbuf *bp) log_redrive_list = bp; spin_unlock_irqrestore(&log_redrive_lock, flags); - wake_up(&jfs_IO_thread_wait); + wake_up_process(jfsIOthread); } @@ -2347,13 +2344,7 @@ int jfsIOWait(void *arg) { struct lbuf *bp; - daemonize("jfsIO"); - - complete(&jfsIOwait); - do { - DECLARE_WAITQUEUE(wq, current); - spin_lock_irq(&log_redrive_lock); while ((bp = log_redrive_list) != 0) { log_redrive_list = bp->l_redrive_next; @@ -2362,21 +2353,19 @@ int jfsIOWait(void *arg) lbmStartIO(bp); spin_lock_irq(&log_redrive_lock); } + spin_unlock_irq(&log_redrive_lock); + if (freezing(current)) { - spin_unlock_irq(&log_redrive_lock); refrigerator(); } else { - add_wait_queue(&jfs_IO_thread_wait, &wq); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&log_redrive_lock); schedule(); current->state = TASK_RUNNING; - remove_wait_queue(&jfs_IO_thread_wait, &wq); } - } while (!jfs_stop_threads); + } while (!kthread_should_stop()); jfs_info("jfsIOWait being killed!"); - complete_and_exit(&jfsIOwait, 0); + return 0; } /* diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index e4978b5b65e..8c6909b8001 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h @@ -389,7 +389,7 @@ struct jfs_log { int eor; /* 4: eor of last record in eol page */ struct lbuf *bp; /* 4: current log page buffer */ - struct semaphore loglock; /* 4: log write serialization lock */ + struct mutex loglock; /* 4: log write serialization lock */ /* syncpt */ int nextsync; /* 4: bytes to write before next syncpt */ diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 8a53981f9f2..5fbaeaadccd 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -104,10 +104,9 @@ static inline int insert_metapage(struct page *page, struct metapage *mp) if (PagePrivate(page)) a = mp_anchor(page); else { - a = kmalloc(sizeof(struct meta_anchor), GFP_NOFS); + a = kzalloc(sizeof(struct meta_anchor), GFP_NOFS); if (!a) return -ENOMEM; - memset(a, 0, sizeof(struct meta_anchor)); set_page_private(page, (unsigned long)a); SetPagePrivate(page); kmap(page); diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h index fcf781bf31c..682cf1a68a1 100644 --- a/fs/jfs/jfs_superblock.h +++ b/fs/jfs/jfs_superblock.h @@ -113,12 +113,9 @@ extern int jfs_mount(struct super_block *); extern int jfs_mount_rw(struct super_block *, int); extern int jfs_umount(struct super_block *); extern int jfs_umount_rw(struct super_block *); - -extern int jfs_stop_threads; -extern struct completion jfsIOwait; -extern wait_queue_head_t jfs_IO_thread_wait; -extern wait_queue_head_t jfs_commit_thread_wait; -extern wait_queue_head_t jfs_sync_thread_wait; extern int jfs_extendfs(struct super_block *, s64, int); +extern struct task_struct *jfsIOthread; +extern struct task_struct *jfsSyncThread; + #endif /*_H_JFS_SUPERBLOCK */ diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 2ddb6b892bc..ac3d66948e8 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -49,6 +49,7 @@ #include <linux/suspend.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/kthread.h> #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_filsys.h" @@ -121,8 +122,7 @@ static DEFINE_SPINLOCK(jfsTxnLock); #define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags) #define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags) -DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait); -DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait); +static DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait); static int jfs_commit_thread_waking; /* @@ -207,7 +207,7 @@ static lid_t txLockAlloc(void) if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) { jfs_info("txLockAlloc tlocks low"); jfs_tlocks_low = 1; - wake_up(&jfs_sync_thread_wait); + wake_up_process(jfsSyncThread); } return lid; @@ -2743,10 +2743,6 @@ int jfs_lazycommit(void *arg) unsigned long flags; struct jfs_sb_info *sbi; - daemonize("jfsCommit"); - - complete(&jfsIOwait); - do { LAZY_LOCK(flags); jfs_commit_thread_waking = 0; /* OK to wake another thread */ @@ -2806,13 +2802,13 @@ int jfs_lazycommit(void *arg) current->state = TASK_RUNNING; remove_wait_queue(&jfs_commit_thread_wait, &wq); } - } while (!jfs_stop_threads); + } while (!kthread_should_stop()); if (!list_empty(&TxAnchor.unlock_queue)) jfs_err("jfs_lazycommit being killed w/pending transactions!"); else jfs_info("jfs_lazycommit being killed\n"); - complete_and_exit(&jfsIOwait, 0); + return 0; } void txLazyUnlock(struct tblock * tblk) @@ -2876,10 +2872,10 @@ restart: */ TXN_UNLOCK(); tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE); - down(&jfs_ip->commit_sem); + mutex_lock(&jfs_ip->commit_mutex); txCommit(tid, 1, &ip, 0); txEnd(tid); - up(&jfs_ip->commit_sem); + mutex_unlock(&jfs_ip->commit_mutex); /* * Just to be safe. I don't know how * long we can run without blocking @@ -2932,10 +2928,6 @@ int jfs_sync(void *arg) int rc; tid_t tid; - daemonize("jfsSync"); - - complete(&jfsIOwait); - do { /* * write each inode on the anonymous inode list @@ -2952,7 +2944,7 @@ int jfs_sync(void *arg) * Inode is being freed */ list_del_init(&jfs_ip->anon_inode_list); - } else if (! down_trylock(&jfs_ip->commit_sem)) { + } else if (! !mutex_trylock(&jfs_ip->commit_mutex)) { /* * inode will be removed from anonymous list * when it is committed @@ -2961,7 +2953,7 @@ int jfs_sync(void *arg) tid = txBegin(ip->i_sb, COMMIT_INODE); rc = txCommit(tid, 1, &ip, 0); txEnd(tid); - up(&jfs_ip->commit_sem); + mutex_unlock(&jfs_ip->commit_mutex); iput(ip); /* @@ -2971,7 +2963,7 @@ int jfs_sync(void *arg) cond_resched(); TXN_LOCK(); } else { - /* We can't get the commit semaphore. It may + /* We can't get the commit mutex. It may * be held by a thread waiting for tlock's * so let's not block here. Save it to * put back on the anon_list. @@ -2996,19 +2988,15 @@ int jfs_sync(void *arg) TXN_UNLOCK(); refrigerator(); } else { - DECLARE_WAITQUEUE(wq, current); - - add_wait_queue(&jfs_sync_thread_wait, &wq); set_current_state(TASK_INTERRUPTIBLE); TXN_UNLOCK(); schedule(); current->state = TASK_RUNNING; - remove_wait_queue(&jfs_sync_thread_wait, &wq); } - } while (!jfs_stop_threads); + } while (!kthread_should_stop()); jfs_info("jfs_sync being killed"); - complete_and_exit(&jfsIOwait, 0); + return 0; } #if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG) diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 4abbe860430..309cee575f7 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -104,8 +104,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); rc = jfs_init_acl(tid, ip, dip); if (rc) @@ -165,8 +165,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -238,8 +238,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); rc = jfs_init_acl(tid, ip, dip); if (rc) @@ -300,8 +300,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -365,8 +365,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); iplist[0] = dip; iplist[1] = ip; @@ -384,8 +384,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) if (rc == -EIO) txAbort(tid, 1); txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); goto out2; } @@ -422,8 +422,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); /* * Truncating the directory index table is not guaranteed. It @@ -488,8 +488,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); iplist[0] = dip; iplist[1] = ip; @@ -503,8 +503,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if (rc == -EIO) txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); IWRITE_UNLOCK(ip); goto out1; } @@ -527,8 +527,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if ((new_size = commitZeroLink(tid, ip)) < 0) { txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); IWRITE_UNLOCK(ip); rc = new_size; goto out1; @@ -556,13 +556,13 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); while (new_size && (rc == 0)) { tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); new_size = xtTruncate_pmap(tid, ip, new_size); if (new_size < 0) { txAbort(tid, 1); /* Marks FS Dirty */ @@ -570,7 +570,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) } else rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC); txEnd(tid); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); } if (ip->i_nlink == 0) @@ -805,8 +805,8 @@ static int jfs_link(struct dentry *old_dentry, tid = txBegin(ip->i_sb, 0); - down(&JFS_IP(dir)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dir)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* * scan parent directory for entry/freespace @@ -847,8 +847,8 @@ static int jfs_link(struct dentry *old_dentry, out: txEnd(tid); - up(&JFS_IP(dir)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dir)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); jfs_info("jfs_link: rc:%d", rc); return rc; @@ -916,8 +916,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); rc = jfs_init_security(tid, ip, dip); if (rc) @@ -1037,8 +1037,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -1141,13 +1141,13 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, */ tid = txBegin(new_dir->i_sb, 0); - down(&JFS_IP(new_dir)->commit_sem); - down(&JFS_IP(old_ip)->commit_sem); + mutex_lock(&JFS_IP(new_dir)->commit_mutex); + mutex_lock(&JFS_IP(old_ip)->commit_mutex); if (old_dir != new_dir) - down(&JFS_IP(old_dir)->commit_sem); + mutex_lock(&JFS_IP(old_dir)->commit_mutex); if (new_ip) { - down(&JFS_IP(new_ip)->commit_sem); + mutex_lock(&JFS_IP(new_ip)->commit_mutex); /* * Change existing directory entry to new inode number */ @@ -1160,10 +1160,10 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (S_ISDIR(new_ip->i_mode)) { new_ip->i_nlink--; if (new_ip->i_nlink) { - up(&JFS_IP(new_dir)->commit_sem); - up(&JFS_IP(old_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_dir)->commit_mutex); + mutex_unlock(&JFS_IP(old_ip)->commit_mutex); if (old_dir != new_dir) - up(&JFS_IP(old_dir)->commit_sem); + mutex_unlock(&JFS_IP(old_dir)->commit_mutex); if (!S_ISDIR(old_ip->i_mode) && new_ip) IWRITE_UNLOCK(new_ip); jfs_error(new_ip->i_sb, @@ -1282,16 +1282,16 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, out4: txEnd(tid); - up(&JFS_IP(new_dir)->commit_sem); - up(&JFS_IP(old_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_dir)->commit_mutex); + mutex_unlock(&JFS_IP(old_ip)->commit_mutex); if (old_dir != new_dir) - up(&JFS_IP(old_dir)->commit_sem); + mutex_unlock(&JFS_IP(old_dir)->commit_mutex); if (new_ip) - up(&JFS_IP(new_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_ip)->commit_mutex); while (new_size && (rc == 0)) { tid = txBegin(new_ip->i_sb, 0); - down(&JFS_IP(new_ip)->commit_sem); + mutex_lock(&JFS_IP(new_ip)->commit_mutex); new_size = xtTruncate_pmap(tid, new_ip, new_size); if (new_size < 0) { txAbort(tid, 1); @@ -1299,7 +1299,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, } else rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC); txEnd(tid); - up(&JFS_IP(new_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_ip)->commit_mutex); } if (new_ip && (new_ip->i_nlink == 0)) set_cflag(COMMIT_Nolink, new_ip); @@ -1361,8 +1361,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, tid = txBegin(dir->i_sb, 0); - down(&JFS_IP(dir)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dir)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); rc = jfs_init_acl(tid, ip, dir); if (rc) @@ -1407,8 +1407,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, out3: txEnd(tid); - up(&JFS_IP(ip)->commit_sem); - up(&JFS_IP(dir)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dir)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -1523,6 +1523,7 @@ struct file_operations jfs_dir_operations = { .read = generic_read_dir, .readdir = jfs_readdir, .fsync = jfs_fsync, + .ioctl = jfs_ioctl, }; static int jfs_ci_hash(struct dentry *dir, struct qstr *this) diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 8d31f133643..18f69e6aa71 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -25,6 +25,7 @@ #include <linux/vfs.h> #include <linux/mount.h> #include <linux/moduleparam.h> +#include <linux/kthread.h> #include <linux/posix_acl.h> #include <asm/uaccess.h> #include <linux/seq_file.h> @@ -54,11 +55,9 @@ static int commit_threads = 0; module_param(commit_threads, int, 0); MODULE_PARM_DESC(commit_threads, "Number of commit threads"); -int jfs_stop_threads; -static pid_t jfsIOthread; -static pid_t jfsCommitThread[MAX_COMMIT_THREADS]; -static pid_t jfsSyncThread; -DECLARE_COMPLETION(jfsIOwait); +static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS]; +struct task_struct *jfsIOthread; +struct task_struct *jfsSyncThread; #ifdef CONFIG_JFS_DEBUG int jfsloglevel = JFS_LOGLEVEL_WARN; @@ -195,7 +194,7 @@ static void jfs_put_super(struct super_block *sb) enum { Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota + Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask }; static match_table_t tokens = { @@ -209,6 +208,9 @@ static match_table_t tokens = { {Opt_ignore, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_grpquota, "grpquota"}, + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_umask, "umask=%u"}, {Opt_err, NULL} }; @@ -313,7 +315,29 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, "JFS: quota operations not supported\n"); break; #endif - + case Opt_uid: + { + char *uid = args[0].from; + sbi->uid = simple_strtoul(uid, &uid, 0); + break; + } + case Opt_gid: + { + char *gid = args[0].from; + sbi->gid = simple_strtoul(gid, &gid, 0); + break; + } + case Opt_umask: + { + char *umask = args[0].from; + sbi->umask = simple_strtoul(umask, &umask, 8); + if (sbi->umask & ~0777) { + printk(KERN_ERR + "JFS: Invalid value of umask\n"); + goto cleanup; + } + break; + } default: printk("jfs: Unrecognized mount option \"%s\" " " or missing value\n", p); @@ -396,12 +420,12 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) if (!new_valid_dev(sb->s_bdev->bd_dev)) return -EOVERFLOW; - sbi = kmalloc(sizeof (struct jfs_sb_info), GFP_KERNEL); + sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL); if (!sbi) return -ENOSPC; - memset(sbi, 0, sizeof (struct jfs_sb_info)); sb->s_fs_info = sbi; sbi->sb = sb; + sbi->uid = sbi->gid = sbi->umask = -1; /* initialize the mount flag and determine the default error handler */ flag = JFS_ERR_REMOUNT_RO; @@ -564,10 +588,14 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb); + if (sbi->uid != -1) + seq_printf(seq, ",uid=%d", sbi->uid); + if (sbi->gid != -1) + seq_printf(seq, ",gid=%d", sbi->gid); + if (sbi->umask != -1) + seq_printf(seq, ",umask=%03o", sbi->umask); if (sbi->flag & JFS_NOINTEGRITY) seq_puts(seq, ",nointegrity"); - else - seq_puts(seq, ",integrity"); #if defined(CONFIG_QUOTA) if (sbi->flag & JFS_USRQUOTA) @@ -617,7 +645,7 @@ static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) memset(jfs_ip, 0, sizeof(struct jfs_inode_info)); INIT_LIST_HEAD(&jfs_ip->anon_inode_list); init_rwsem(&jfs_ip->rdwrlock); - init_MUTEX(&jfs_ip->commit_sem); + mutex_init(&jfs_ip->commit_mutex); init_rwsem(&jfs_ip->xattr_sem); spin_lock_init(&jfs_ip->ag_lock); jfs_ip->active_ag = -1; @@ -661,12 +689,12 @@ static int __init init_jfs_fs(void) /* * I/O completion thread (endio) */ - jfsIOthread = kernel_thread(jfsIOWait, NULL, CLONE_KERNEL); - if (jfsIOthread < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsIOthread); + jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO"); + if (IS_ERR(jfsIOthread)) { + rc = PTR_ERR(jfsIOthread); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); goto end_txmngr; } - wait_for_completion(&jfsIOwait); /* Wait until thread starts */ if (commit_threads < 1) commit_threads = num_online_cpus(); @@ -674,24 +702,21 @@ static int __init init_jfs_fs(void) commit_threads = MAX_COMMIT_THREADS; for (i = 0; i < commit_threads; i++) { - jfsCommitThread[i] = kernel_thread(jfs_lazycommit, NULL, - CLONE_KERNEL); - if (jfsCommitThread[i] < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", - jfsCommitThread[i]); + jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL, "jfsCommit"); + if (IS_ERR(jfsCommitThread[i])) { + rc = PTR_ERR(jfsCommitThread[i]); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); commit_threads = i; goto kill_committask; } - /* Wait until thread starts */ - wait_for_completion(&jfsIOwait); } - jfsSyncThread = kernel_thread(jfs_sync, NULL, CLONE_KERNEL); - if (jfsSyncThread < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsSyncThread); + jfsSyncThread = kthread_run(jfs_sync, NULL, "jfsSync"); + if (IS_ERR(jfsSyncThread)) { + rc = PTR_ERR(jfsSyncThread); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); goto kill_committask; } - wait_for_completion(&jfsIOwait); /* Wait until thread starts */ #ifdef PROC_FS_JFS jfs_proc_init(); @@ -700,13 +725,9 @@ static int __init init_jfs_fs(void) return register_filesystem(&jfs_fs_type); kill_committask: - jfs_stop_threads = 1; - wake_up_all(&jfs_commit_thread_wait); for (i = 0; i < commit_threads; i++) - wait_for_completion(&jfsIOwait); - - wake_up(&jfs_IO_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait for thread exit */ + kthread_stop(jfsCommitThread[i]); + kthread_stop(jfsIOthread); end_txmngr: txExit(); free_metapage: @@ -722,16 +743,13 @@ static void __exit exit_jfs_fs(void) jfs_info("exit_jfs_fs called"); - jfs_stop_threads = 1; txExit(); metapage_exit(); - wake_up(&jfs_IO_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait until IO thread exits */ - wake_up_all(&jfs_commit_thread_wait); + + kthread_stop(jfsIOthread); for (i = 0; i < commit_threads; i++) - wait_for_completion(&jfsIOwait); - wake_up(&jfs_sync_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait until Sync thread exits */ + kthread_stop(jfsCommitThread[i]); + kthread_stop(jfsSyncThread); #ifdef PROC_FS_JFS jfs_proc_clean(); #endif diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index f23048f9471..9bc5b7c055c 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -934,13 +934,13 @@ int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, } tid = txBegin(inode->i_sb, 0); - down(&ji->commit_sem); + mutex_lock(&ji->commit_mutex); rc = __jfs_setxattr(tid, dentry->d_inode, name, value, value_len, flags); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); - up(&ji->commit_sem); + mutex_unlock(&ji->commit_mutex); return rc; } @@ -1093,12 +1093,12 @@ int jfs_removexattr(struct dentry *dentry, const char *name) return rc; tid = txBegin(inode->i_sb, 0); - down(&ji->commit_sem); + mutex_lock(&ji->commit_mutex); rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); - up(&ji->commit_sem); + mutex_unlock(&ji->commit_mutex); return rc; } diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 220058d8616..970b6a6aa33 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -662,12 +662,18 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) * reclaimed while we're stuck in the unlock call. */ fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED; + /* + * Note: the server is supposed to either grant us the unlock + * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either + * case, we want to unlock. + */ + do_vfs_lock(fl); + if (req->a_flags & RPC_TASK_ASYNC) { status = nlmclnt_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); /* Hrmf... Do the unlock early since locks_remove_posix() * really expects us to free the lock synchronously */ - do_vfs_lock(fl); if (status < 0) { nlmclnt_release_lockargs(req); kfree(req); @@ -680,7 +686,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) if (status < 0) return status; - do_vfs_lock(fl); if (resp->status == NLM_LCK_GRANTED) return 0; diff --git a/fs/namei.c b/fs/namei.c index e28de846c59..8dc2b038d5d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2224,13 +2224,17 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de * and other special files. --ADM */ asmlinkage long sys_linkat(int olddfd, const char __user *oldname, - int newdfd, const char __user *newname) + int newdfd, const char __user *newname, + int flags) { struct dentry *new_dentry; struct nameidata nd, old_nd; int error; char * to; + if (flags != 0) + return -EINVAL; + to = getname(newname); if (IS_ERR(to)) return PTR_ERR(to); @@ -2263,7 +2267,7 @@ exit: asmlinkage long sys_link(const char __user *oldname, const char __user *newname) { - return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname); + return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); } /* @@ -2609,13 +2613,15 @@ void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) } } -int page_symlink(struct inode *inode, const char *symname, int len) +int __page_symlink(struct inode *inode, const char *symname, int len, + gfp_t gfp_mask) { struct address_space *mapping = inode->i_mapping; - struct page *page = grab_cache_page(mapping, 0); + struct page *page; int err = -ENOMEM; char *kaddr; + page = find_or_create_page(mapping, 0, gfp_mask); if (!page) goto fail; err = mapping->a_ops->prepare_write(NULL, page, 0, len-1); @@ -2650,6 +2656,12 @@ fail: return err; } +int page_symlink(struct inode *inode, const char *symname, int len) +{ + return __page_symlink(inode, symname, len, + mapping_gfp_mask(inode->i_mapping)); +} + struct inode_operations page_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, @@ -2668,6 +2680,7 @@ EXPORT_SYMBOL(lookup_one_len); EXPORT_SYMBOL(page_follow_link_light); EXPORT_SYMBOL(page_put_link); EXPORT_SYMBOL(page_readlink); +EXPORT_SYMBOL(__page_symlink); EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(path_lookup); diff --git a/fs/namespace.c b/fs/namespace.c index 058a44865be..39c81a8d631 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1338,7 +1338,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL); if (!new_ns) - goto out; + return NULL; atomic_set(&new_ns->count, 1); INIT_LIST_HEAD(&new_ns->list); @@ -1352,7 +1352,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) if (!new_ns->root) { up_write(&namespace_sem); kfree(new_ns); - goto out; + return NULL; } spin_lock(&vfsmount_lock); list_add_tail(&new_ns->list, &new_ns->root->mnt_list); @@ -1393,7 +1393,6 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) if (altrootmnt) mntput(altrootmnt); -out: return new_ns; } diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 04ab2fc360e..4e9b3a1b36c 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -57,6 +57,7 @@ #define NFSDBG_FACILITY NFSDBG_VFS #define MAX_DIRECTIO_SIZE (4096UL << PAGE_SHIFT) +static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty); static kmem_cache_t *nfs_direct_cachep; /* @@ -107,6 +108,15 @@ nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, page_count, (rw == READ), 0, *pages, NULL); up_read(¤t->mm->mmap_sem); + /* + * If we got fewer pages than expected from get_user_pages(), + * the user buffer runs off the end of a mapping; return EFAULT. + */ + if (result >= 0 && result < page_count) { + nfs_free_user_pages(*pages, result, 0); + *pages = NULL; + result = -EFAULT; + } } return result; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 984ca3454d0..f8c0066e02e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1430,7 +1430,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, if (status == 0) status = nfs4_do_fsinfo(server, fhandle, info); out: - return status; + return nfs4_map_errors(status); } static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) diff --git a/fs/nfsctl.c b/fs/nfsctl.c index 0d4cf948606..1c72c7f85dd 100644 --- a/fs/nfsctl.c +++ b/fs/nfsctl.c @@ -98,10 +98,8 @@ asmlinkage sys_nfsservctl(int cmd, struct nfsctl_arg __user *arg, void __user *r if (copy_from_user(&version, &arg->ca_version, sizeof(int))) return -EFAULT; - if (version != NFSCTL_VERSION) { - printk(KERN_WARNING "nfsd: incompatible version in syscall.\n"); + if (version != NFSCTL_VERSION) return -EINVAL; - } if (cmd < 0 || cmd >= sizeof(map)/sizeof(map[0]) || !map[cmd].name) return -EINVAL; diff --git a/fs/nls/Kconfig b/fs/nls/Kconfig index 0ab8f00bdbb..976ecccd6f5 100644 --- a/fs/nls/Kconfig +++ b/fs/nls/Kconfig @@ -491,7 +491,7 @@ config NLS_KOI8_U (koi8-u) and Belarusian (koi8-ru) character sets. config NLS_UTF8 - tristate "NLS UTF8" + tristate "NLS UTF-8" depends on NLS help If you want to display filenames with native language characters diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index fd741cea570..636593bf4d1 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c @@ -74,6 +74,7 @@ struct mlog_attribute { #define define_mask(_name) { \ .attr = { \ .name = #_name, \ + .owner = THIS_MODULE, \ .mode = S_IRUGO | S_IWUSR, \ }, \ .mask = ML_##_name, \ diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index e8c56a3d9c6..2cadc3009c8 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h @@ -256,7 +256,7 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits; } \ } while (0) -#if (BITS_PER_LONG == 32) || defined(CONFIG_X86_64) +#if (BITS_PER_LONG == 32) || defined(CONFIG_X86_64) || (defined(CONFIG_UML_X86) && defined(CONFIG_64BIT)) #define MLFi64 "lld" #define MLFu64 "llu" #define MLFx64 "llx" diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index cf7828f2336..e1fceb8aa32 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -756,7 +756,7 @@ static int __init init_o2nm(void) if (!ocfs2_table_header) { printk(KERN_ERR "nodemanager: unable to register sysctl\n"); ret = -ENOMEM; /* or something. */ - goto out; + goto out_o2net; } ret = o2net_register_hb_callbacks(); @@ -780,6 +780,8 @@ out_callbacks: o2net_unregister_hb_callbacks(); out_sysctl: unregister_sysctl_table(ocfs2_table_header); +out_o2net: + o2net_exit(); out: return ret; } diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index d22d4cf08db..0f60cc0d398 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -1318,7 +1318,7 @@ static void o2net_start_connect(void *arg) { struct o2net_node *nn = arg; struct o2net_sock_container *sc = NULL; - struct o2nm_node *node = NULL; + struct o2nm_node *node = NULL, *mynode = NULL; struct socket *sock = NULL; struct sockaddr_in myaddr = {0, }, remoteaddr = {0, }; int ret = 0; @@ -1334,6 +1334,12 @@ static void o2net_start_connect(void *arg) goto out; } + mynode = o2nm_get_node_by_num(o2nm_this_node()); + if (mynode == NULL) { + ret = 0; + goto out; + } + spin_lock(&nn->nn_lock); /* see if we already have one pending or have given up */ if (nn->nn_sc || nn->nn_persistent_error) @@ -1361,12 +1367,14 @@ static void o2net_start_connect(void *arg) sock->sk->sk_allocation = GFP_ATOMIC; myaddr.sin_family = AF_INET; + myaddr.sin_addr.s_addr = (__force u32)mynode->nd_ipv4_address; myaddr.sin_port = (__force u16)htons(0); /* any port */ ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr, sizeof(myaddr)); if (ret) { - mlog(0, "bind failed: %d\n", ret); + mlog(ML_ERROR, "bind failed with %d at address %u.%u.%u.%u\n", + ret, NIPQUAD(mynode->nd_ipv4_address)); goto out; } @@ -1407,6 +1415,8 @@ out: sc_put(sc); if (node) o2nm_node_put(node); + if (mynode) + o2nm_node_put(mynode); return; } diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h index a6f4585501c..616ff2b8434 100644 --- a/fs/ocfs2/cluster/tcp.h +++ b/fs/ocfs2/cluster/tcp.h @@ -85,13 +85,10 @@ enum { O2NET_DRIVER_READY, }; -int o2net_init_tcp_sock(struct inode *inode); int o2net_send_message(u32 msg_type, u32 key, void *data, u32 len, u8 target_node, int *status); int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *vec, size_t veclen, u8 target_node, int *status); -int o2net_broadcast_message(u32 msg_type, u32 key, void *data, u32 len, - struct inode *group); int o2net_register_handler(u32 msg_type, u32 key, u32 max_len, o2net_msg_handler_func *func, void *data, @@ -107,7 +104,5 @@ void o2net_disconnect_node(struct o2nm_node *node); int o2net_init(void); void o2net_exit(void); -int o2net_proc_init(struct proc_dir_entry *parent); -void o2net_proc_exit(struct proc_dir_entry *parent); #endif /* O2CLUSTER_TCP_H */ diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index 23ceaa7127b..9c772583744 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h @@ -37,9 +37,7 @@ #define DLM_THREAD_SHUFFLE_INTERVAL 5 // flush everything every 5 passes #define DLM_THREAD_MS 200 // flush at least every 200 ms -#define DLM_HASH_BITS 7 -#define DLM_HASH_SIZE (1 << DLM_HASH_BITS) -#define DLM_HASH_MASK (DLM_HASH_SIZE - 1) +#define DLM_HASH_BUCKETS (PAGE_SIZE / sizeof(struct hlist_head)) enum dlm_ast_type { DLM_AST = 0, @@ -87,7 +85,7 @@ enum dlm_ctxt_state { struct dlm_ctxt { struct list_head list; - struct list_head *resources; + struct hlist_head *lockres_hash; struct list_head dirty_list; struct list_head purge_list; struct list_head pending_asts; @@ -217,7 +215,7 @@ struct dlm_lock_resource { /* WARNING: Please see the comment in dlm_init_lockres before * adding fields here. */ - struct list_head list; + struct hlist_node hash_node; struct kref refs; /* please keep these next 3 in this order diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c index f339fe27975..54f61b76ab5 100644 --- a/fs/ocfs2/dlm/dlmdebug.c +++ b/fs/ocfs2/dlm/dlmdebug.c @@ -117,8 +117,8 @@ EXPORT_SYMBOL_GPL(dlm_print_one_lock); void dlm_dump_lock_resources(struct dlm_ctxt *dlm) { struct dlm_lock_resource *res; - struct list_head *iter; - struct list_head *bucket; + struct hlist_node *iter; + struct hlist_head *bucket; int i; mlog(ML_NOTICE, "struct dlm_ctxt: %s, node=%u, key=%u\n", @@ -129,12 +129,10 @@ void dlm_dump_lock_resources(struct dlm_ctxt *dlm) } spin_lock(&dlm->spinlock); - for (i=0; i<DLM_HASH_SIZE; i++) { - bucket = &(dlm->resources[i]); - list_for_each(iter, bucket) { - res = list_entry(iter, struct dlm_lock_resource, list); + for (i=0; i<DLM_HASH_BUCKETS; i++) { + bucket = &(dlm->lockres_hash[i]); + hlist_for_each_entry(res, iter, bucket, hash_node) dlm_print_one_lock_resource(res); - } } spin_unlock(&dlm->spinlock); } diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 6ee30837389..8f3a9e3106f 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -77,26 +77,26 @@ static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm); void __dlm_unhash_lockres(struct dlm_lock_resource *lockres) { - list_del_init(&lockres->list); + hlist_del_init(&lockres->hash_node); dlm_lockres_put(lockres); } void __dlm_insert_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) { - struct list_head *bucket; + struct hlist_head *bucket; struct qstr *q; assert_spin_locked(&dlm->spinlock); q = &res->lockname; q->hash = full_name_hash(q->name, q->len); - bucket = &(dlm->resources[q->hash & DLM_HASH_MASK]); + bucket = &(dlm->lockres_hash[q->hash % DLM_HASH_BUCKETS]); /* get a reference for our hashtable */ dlm_lockres_get(res); - list_add_tail(&res->list, bucket); + hlist_add_head(&res->hash_node, bucket); } struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, @@ -104,9 +104,9 @@ struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, unsigned int len) { unsigned int hash; - struct list_head *iter; + struct hlist_node *iter; struct dlm_lock_resource *tmpres=NULL; - struct list_head *bucket; + struct hlist_head *bucket; mlog_entry("%.*s\n", len, name); @@ -114,11 +114,11 @@ struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, hash = full_name_hash(name, len); - bucket = &(dlm->resources[hash & DLM_HASH_MASK]); + bucket = &(dlm->lockres_hash[hash % DLM_HASH_BUCKETS]); /* check for pre-existing lock */ - list_for_each(iter, bucket) { - tmpres = list_entry(iter, struct dlm_lock_resource, list); + hlist_for_each(iter, bucket) { + tmpres = hlist_entry(iter, struct dlm_lock_resource, hash_node); if (tmpres->lockname.len == len && memcmp(tmpres->lockname.name, name, len) == 0) { dlm_lockres_get(tmpres); @@ -193,8 +193,8 @@ static int dlm_wait_on_domain_helper(const char *domain) static void dlm_free_ctxt_mem(struct dlm_ctxt *dlm) { - if (dlm->resources) - free_page((unsigned long) dlm->resources); + if (dlm->lockres_hash) + free_page((unsigned long) dlm->lockres_hash); if (dlm->name) kfree(dlm->name); @@ -303,10 +303,10 @@ static void dlm_migrate_all_locks(struct dlm_ctxt *dlm) mlog(0, "Migrating locks from domain %s\n", dlm->name); restart: spin_lock(&dlm->spinlock); - for (i=0; i<DLM_HASH_SIZE; i++) { - while (!list_empty(&dlm->resources[i])) { - res = list_entry(dlm->resources[i].next, - struct dlm_lock_resource, list); + for (i = 0; i < DLM_HASH_BUCKETS; i++) { + while (!hlist_empty(&dlm->lockres_hash[i])) { + res = hlist_entry(dlm->lockres_hash[i].first, + struct dlm_lock_resource, hash_node); /* need reference when manually grabbing lockres */ dlm_lockres_get(res); /* this should unhash the lockres @@ -1191,18 +1191,17 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, goto leave; } - dlm->resources = (struct list_head *) __get_free_page(GFP_KERNEL); - if (!dlm->resources) { + dlm->lockres_hash = (struct hlist_head *) __get_free_page(GFP_KERNEL); + if (!dlm->lockres_hash) { mlog_errno(-ENOMEM); kfree(dlm->name); kfree(dlm); dlm = NULL; goto leave; } - memset(dlm->resources, 0, PAGE_SIZE); - for (i=0; i<DLM_HASH_SIZE; i++) - INIT_LIST_HEAD(&dlm->resources[i]); + for (i=0; i<DLM_HASH_BUCKETS; i++) + INIT_HLIST_HEAD(&dlm->lockres_hash[i]); strcpy(dlm->name, domain); dlm->key = key; diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 2e2e95e6949..847dd3cc4cf 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -564,7 +564,7 @@ static void dlm_lockres_release(struct kref *kref) /* By the time we're ready to blow this guy away, we shouldn't * be on any lists. */ - BUG_ON(!list_empty(&res->list)); + BUG_ON(!hlist_unhashed(&res->hash_node)); BUG_ON(!list_empty(&res->granted)); BUG_ON(!list_empty(&res->converting)); BUG_ON(!list_empty(&res->blocked)); @@ -605,7 +605,7 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm, init_waitqueue_head(&res->wq); spin_lock_init(&res->spinlock); - INIT_LIST_HEAD(&res->list); + INIT_HLIST_NODE(&res->hash_node); INIT_LIST_HEAD(&res->granted); INIT_LIST_HEAD(&res->converting); INIT_LIST_HEAD(&res->blocked); diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index ed76bda1a53..1e232000f3f 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -1693,7 +1693,10 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm, u8 dead_node, u8 new_master) { int i; - struct list_head *iter, *iter2, *bucket; + struct list_head *iter, *iter2; + struct hlist_node *hash_iter; + struct hlist_head *bucket; + struct dlm_lock_resource *res; mlog_entry_void(); @@ -1717,10 +1720,9 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm, * for now we need to run the whole hash, clear * the RECOVERING state and set the owner * if necessary */ - for (i=0; i<DLM_HASH_SIZE; i++) { - bucket = &(dlm->resources[i]); - list_for_each(iter, bucket) { - res = list_entry (iter, struct dlm_lock_resource, list); + for (i = 0; i < DLM_HASH_BUCKETS; i++) { + bucket = &(dlm->lockres_hash[i]); + hlist_for_each_entry(res, hash_iter, bucket, hash_node) { if (res->state & DLM_LOCK_RES_RECOVERING) { if (res->owner == dead_node) { mlog(0, "(this=%u) res %.*s owner=%u " @@ -1852,10 +1854,10 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) { - struct list_head *iter; + struct hlist_node *iter; struct dlm_lock_resource *res; int i; - struct list_head *bucket; + struct hlist_head *bucket; struct dlm_lock *lock; @@ -1876,10 +1878,9 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) * can be kicked again to see if any ASTs or BASTs * need to be fired as a result. */ - for (i=0; i<DLM_HASH_SIZE; i++) { - bucket = &(dlm->resources[i]); - list_for_each(iter, bucket) { - res = list_entry (iter, struct dlm_lock_resource, list); + for (i = 0; i < DLM_HASH_BUCKETS; i++) { + bucket = &(dlm->lockres_hash[i]); + hlist_for_each_entry(res, iter, bucket, hash_node) { /* always prune any $RECOVERY entries for dead nodes, * otherwise hangs can occur during later recovery */ if (dlm_is_recovery_lock(res->lockname.name, diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index b6ba292e954..e6f207eebab 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c @@ -181,6 +181,12 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode, ret = -EBADR; if (rec_end > OCFS2_I(inode)->ip_clusters) { mlog_errno(ret); + ocfs2_error(inode->i_sb, + "Extent %d at e_blkno %"MLFu64" of inode %"MLFu64" goes past ip_clusters of %u\n", + i, + le64_to_cpu(rec->e_blkno), + OCFS2_I(inode)->ip_blkno, + OCFS2_I(inode)->ip_clusters); goto out_free; } @@ -226,6 +232,12 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode, ret = -EBADR; if (blkno) { mlog_errno(ret); + ocfs2_error(inode->i_sb, + "Multiple extents for (cpos = %u, clusters = %u) on inode %"MLFu64"; e_blkno %"MLFu64" and rec %d at e_blkno %"MLFu64"\n", + cpos, clusters, + OCFS2_I(inode)->ip_blkno, + blkno, i, + le64_to_cpu(rec->e_blkno)); goto out_free; } @@ -238,6 +250,10 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode, */ ret = -EBADR; if (!blkno) { + ocfs2_error(inode->i_sb, + "No record found for (cpos = %u, clusters = %u) on inode %"MLFu64"\n", + cpos, clusters, + OCFS2_I(inode)->ip_blkno); mlog_errno(ret); goto out_free; } @@ -266,6 +282,20 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode, for (i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) { rec = &el->l_recs[i]; + + if ((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) > + OCFS2_I(inode)->ip_clusters) { + ret = -EBADR; + mlog_errno(ret); + ocfs2_error(inode->i_sb, + "Extent %d at e_blkno %"MLFu64" of inode %"MLFu64" goes past ip_clusters of %u\n", + i, + le64_to_cpu(rec->e_blkno), + OCFS2_I(inode)->ip_blkno, + OCFS2_I(inode)->ip_clusters); + return ret; + } + ret = ocfs2_extent_map_insert(inode, rec, le16_to_cpu(el->l_tree_depth)); if (ret) { @@ -526,6 +556,10 @@ static int ocfs2_extent_map_insert(struct inode *inode, OCFS2_I(inode)->ip_map.em_clusters) { ret = -EBADR; mlog_errno(ret); + ocfs2_error(inode->i_sb, + "Zero e_clusters on non-tail extent record at e_blkno %"MLFu64" on inode %"MLFu64"\n", + le64_to_cpu(rec->e_blkno), + OCFS2_I(inode)->ip_blkno); return ret; } @@ -588,12 +622,12 @@ static int ocfs2_extent_map_insert(struct inode *inode, * Existing record in the extent map: * * cpos = 10, len = 10 - * |---------| + * |---------| * * New Record: * * cpos = 10, len = 20 - * |------------------| + * |------------------| * * The passed record is the new on-disk record. The new_clusters value * is how many clusters were added to the file. If the append is a diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 1715bc90e70..8a4048b55fd 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -933,9 +933,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, struct file *filp = iocb->ki_filp; struct inode *inode = filp->f_dentry->d_inode; loff_t newsize, saved_pos; -#ifdef OCFS2_ORACORE_WORKAROUNDS - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); -#endif mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf, (unsigned int)count, @@ -951,14 +948,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, return -EIO; } -#ifdef OCFS2_ORACORE_WORKAROUNDS - /* ugh, work around some applications which open everything O_DIRECT + - * O_APPEND and really don't mean to use O_DIRECT. */ - if (osb->s_mount_opt & OCFS2_MOUNT_COMPAT_OCFS && - (filp->f_flags & O_APPEND) && (filp->f_flags & O_DIRECT)) - filp->f_flags &= ~O_DIRECT; -#endif - mutex_lock(&inode->i_mutex); /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ if (filp->f_flags & O_DIRECT) { @@ -1079,27 +1068,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_rw_locked(iocb); -#ifdef OCFS2_ORACORE_WORKAROUNDS - if (osb->s_mount_opt & OCFS2_MOUNT_COMPAT_OCFS && - filp->f_flags & O_DIRECT) { - unsigned int saved_flags = filp->f_flags; - int sector_size = 1 << osb->s_sectsize_bits; - - if ((saved_pos & (sector_size - 1)) || - (count & (sector_size - 1)) || - ((unsigned long)buf & (sector_size - 1))) { - filp->f_flags |= O_SYNC; - filp->f_flags &= ~O_DIRECT; - } - - ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, - &iocb->ki_pos); - - filp->f_flags = saved_flags; - } else -#endif - ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, - &iocb->ki_pos); + ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); /* buffered aio wouldn't have proper lock coverage today */ BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT)); @@ -1140,9 +1109,6 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, int ret = 0, rw_level = -1, have_alloc_sem = 0; struct file *filp = iocb->ki_filp; struct inode *inode = filp->f_dentry->d_inode; -#ifdef OCFS2_ORACORE_WORKAROUNDS - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); -#endif mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf, (unsigned int)count, @@ -1155,21 +1121,6 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, goto bail; } -#ifdef OCFS2_ORACORE_WORKAROUNDS - if (osb->s_mount_opt & OCFS2_MOUNT_COMPAT_OCFS) { - if (filp->f_flags & O_DIRECT) { - int sector_size = 1 << osb->s_sectsize_bits; - - if ((pos & (sector_size - 1)) || - (count & (sector_size - 1)) || - ((unsigned long)buf & (sector_size - 1)) || - (i_size_read(inode) & (sector_size -1))) { - filp->f_flags &= ~O_DIRECT; - } - } - } -#endif - /* * buffered reads protect themselves in ->readpage(). O_DIRECT reads * need locks to protect pending reads from racing with truncate. diff --git a/fs/ocfs2/heartbeat.c b/fs/ocfs2/heartbeat.c index 0bbd22f46c8..cbfd45a97a6 100644 --- a/fs/ocfs2/heartbeat.c +++ b/fs/ocfs2/heartbeat.c @@ -67,6 +67,7 @@ void ocfs2_init_node_maps(struct ocfs2_super *osb) ocfs2_node_map_init(&osb->mounted_map); ocfs2_node_map_init(&osb->recovery_map); ocfs2_node_map_init(&osb->umount_map); + ocfs2_node_map_init(&osb->osb_recovering_orphan_dirs); } static void ocfs2_do_node_down(int node_num, diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 8122489c576..315472a5c19 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -41,6 +41,7 @@ #include "dlmglue.h" #include "extent_map.h" #include "file.h" +#include "heartbeat.h" #include "inode.h" #include "journal.h" #include "namei.h" @@ -544,6 +545,42 @@ bail: return status; } +/* + * Serialize with orphan dir recovery. If the process doing + * recovery on this orphan dir does an iget() with the dir + * i_mutex held, we'll deadlock here. Instead we detect this + * and exit early - recovery will wipe this inode for us. + */ +static int ocfs2_check_orphan_recovery_state(struct ocfs2_super *osb, + int slot) +{ + int ret = 0; + + spin_lock(&osb->osb_lock); + if (ocfs2_node_map_test_bit(osb, &osb->osb_recovering_orphan_dirs, slot)) { + mlog(0, "Recovery is happening on orphan dir %d, will skip " + "this inode\n", slot); + ret = -EDEADLK; + goto out; + } + /* This signals to the orphan recovery process that it should + * wait for us to handle the wipe. */ + osb->osb_orphan_wipes[slot]++; +out: + spin_unlock(&osb->osb_lock); + return ret; +} + +static void ocfs2_signal_wipe_completion(struct ocfs2_super *osb, + int slot) +{ + spin_lock(&osb->osb_lock); + osb->osb_orphan_wipes[slot]--; + spin_unlock(&osb->osb_lock); + + wake_up(&osb->osb_wipe_event); +} + static int ocfs2_wipe_inode(struct inode *inode, struct buffer_head *di_bh) { @@ -555,6 +592,11 @@ static int ocfs2_wipe_inode(struct inode *inode, /* We've already voted on this so it should be readonly - no * spinlock needed. */ orphaned_slot = OCFS2_I(inode)->ip_orphaned_slot; + + status = ocfs2_check_orphan_recovery_state(osb, orphaned_slot); + if (status) + return status; + orphan_dir_inode = ocfs2_get_system_file_inode(osb, ORPHAN_DIR_SYSTEM_INODE, orphaned_slot); @@ -597,6 +639,7 @@ bail_unlock_dir: brelse(orphan_dir_bh); bail: iput(orphan_dir_inode); + ocfs2_signal_wipe_completion(osb, orphaned_slot); return status; } @@ -822,7 +865,8 @@ void ocfs2_delete_inode(struct inode *inode) status = ocfs2_wipe_inode(inode, di_bh); if (status < 0) { - mlog_errno(status); + if (status != -EDEADLK) + mlog_errno(status); goto bail_unlock_inode; } diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index d329c9df90a..4be801f4559 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -1408,21 +1408,17 @@ bail: return status; } -static int ocfs2_recover_orphans(struct ocfs2_super *osb, - int slot) +static int ocfs2_queue_orphans(struct ocfs2_super *osb, + int slot, + struct inode **head) { - int status = 0; - int have_disk_lock = 0; - struct inode *inode = NULL; - struct inode *iter; + int status; struct inode *orphan_dir_inode = NULL; + struct inode *iter; unsigned long offset, blk, local; struct buffer_head *bh = NULL; struct ocfs2_dir_entry *de; struct super_block *sb = osb->sb; - struct ocfs2_inode_info *oi; - - mlog(0, "Recover inodes from orphan dir in slot %d\n", slot); orphan_dir_inode = ocfs2_get_system_file_inode(osb, ORPHAN_DIR_SYSTEM_INODE, @@ -1430,17 +1426,15 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, if (!orphan_dir_inode) { status = -ENOENT; mlog_errno(status); - goto out; - } + return status; + } mutex_lock(&orphan_dir_inode->i_mutex); status = ocfs2_meta_lock(orphan_dir_inode, NULL, NULL, 0); if (status < 0) { - mutex_unlock(&orphan_dir_inode->i_mutex); mlog_errno(status); goto out; } - have_disk_lock = 1; offset = 0; iter = NULL; @@ -1451,11 +1445,10 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, if (!bh) status = -EINVAL; if (status < 0) { - mutex_unlock(&orphan_dir_inode->i_mutex); if (bh) brelse(bh); mlog_errno(status); - goto out; + goto out_unlock; } local = 0; @@ -1465,11 +1458,10 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, if (!ocfs2_check_dir_entry(orphan_dir_inode, de, bh, local)) { - mutex_unlock(&orphan_dir_inode->i_mutex); status = -EINVAL; mlog_errno(status); brelse(bh); - goto out; + goto out_unlock; } local += le16_to_cpu(de->rec_len); @@ -1504,18 +1496,95 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, mlog(0, "queue orphan %"MLFu64"\n", OCFS2_I(iter)->ip_blkno); - OCFS2_I(iter)->ip_next_orphan = inode; - inode = iter; + /* No locking is required for the next_orphan + * queue as there is only ever a single + * process doing orphan recovery. */ + OCFS2_I(iter)->ip_next_orphan = *head; + *head = iter; } brelse(bh); } - mutex_unlock(&orphan_dir_inode->i_mutex); +out_unlock: ocfs2_meta_unlock(orphan_dir_inode, 0); - have_disk_lock = 0; - +out: + mutex_unlock(&orphan_dir_inode->i_mutex); iput(orphan_dir_inode); - orphan_dir_inode = NULL; + return status; +} + +static int ocfs2_orphan_recovery_can_continue(struct ocfs2_super *osb, + int slot) +{ + int ret; + + spin_lock(&osb->osb_lock); + ret = !osb->osb_orphan_wipes[slot]; + spin_unlock(&osb->osb_lock); + return ret; +} + +static void ocfs2_mark_recovering_orphan_dir(struct ocfs2_super *osb, + int slot) +{ + spin_lock(&osb->osb_lock); + /* Mark ourselves such that new processes in delete_inode() + * know to quit early. */ + ocfs2_node_map_set_bit(osb, &osb->osb_recovering_orphan_dirs, slot); + while (osb->osb_orphan_wipes[slot]) { + /* If any processes are already in the middle of an + * orphan wipe on this dir, then we need to wait for + * them. */ + spin_unlock(&osb->osb_lock); + wait_event_interruptible(osb->osb_wipe_event, + ocfs2_orphan_recovery_can_continue(osb, slot)); + spin_lock(&osb->osb_lock); + } + spin_unlock(&osb->osb_lock); +} + +static void ocfs2_clear_recovering_orphan_dir(struct ocfs2_super *osb, + int slot) +{ + ocfs2_node_map_clear_bit(osb, &osb->osb_recovering_orphan_dirs, slot); +} + +/* + * Orphan recovery. Each mounted node has it's own orphan dir which we + * must run during recovery. Our strategy here is to build a list of + * the inodes in the orphan dir and iget/iput them. The VFS does + * (most) of the rest of the work. + * + * Orphan recovery can happen at any time, not just mount so we have a + * couple of extra considerations. + * + * - We grab as many inodes as we can under the orphan dir lock - + * doing iget() outside the orphan dir risks getting a reference on + * an invalid inode. + * - We must be sure not to deadlock with other processes on the + * system wanting to run delete_inode(). This can happen when they go + * to lock the orphan dir and the orphan recovery process attempts to + * iget() inside the orphan dir lock. This can be avoided by + * advertising our state to ocfs2_delete_inode(). + */ +static int ocfs2_recover_orphans(struct ocfs2_super *osb, + int slot) +{ + int ret = 0; + struct inode *inode = NULL; + struct inode *iter; + struct ocfs2_inode_info *oi; + + mlog(0, "Recover inodes from orphan dir in slot %d\n", slot); + + ocfs2_mark_recovering_orphan_dir(osb, slot); + ret = ocfs2_queue_orphans(osb, slot, &inode); + ocfs2_clear_recovering_orphan_dir(osb, slot); + + /* Error here should be noted, but we want to continue with as + * many queued inodes as we've got. */ + if (ret) + mlog_errno(ret); while (inode) { oi = OCFS2_I(inode); @@ -1541,14 +1610,7 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, inode = iter; } -out: - if (have_disk_lock) - ocfs2_meta_unlock(orphan_dir_inode, 0); - - if (orphan_dir_inode) - iput(orphan_dir_inode); - - return status; + return ret; } static int ocfs2_wait_on_mount(struct ocfs2_super *osb) diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 8d8e4779df9..e89de9b6e49 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -174,9 +174,6 @@ enum ocfs2_mount_options OCFS2_MOUNT_NOINTR = 1 << 2, /* Don't catch signals */ OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */ OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */ -#ifdef OCFS2_ORACORE_WORKAROUNDS - OCFS2_MOUNT_COMPAT_OCFS = 1 << 30, /* ocfs1 compatibility mode */ -#endif }; #define OCFS2_OSB_SOFT_RO 0x0001 @@ -290,6 +287,10 @@ struct ocfs2_super struct inode *osb_tl_inode; struct buffer_head *osb_tl_bh; struct work_struct osb_truncate_log_wq; + + struct ocfs2_node_map osb_recovering_orphan_dirs; + unsigned int *osb_orphan_wipes; + wait_queue_head_t osb_wipe_event; }; #define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info) diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index dfb8a5bedfc..c5b1ac547c1 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -138,7 +138,6 @@ /* Journal limits (in bytes) */ #define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024) -#define OCFS2_MAX_JOURNAL_SIZE (500 * 1024 * 1024) struct ocfs2_system_inode_info { char *si_name; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 046824b6b62..09e1c57a86a 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -959,7 +959,7 @@ static int ocfs2_initialize_mem_caches(void) ocfs2_lock_cache = kmem_cache_create("ocfs2_lock", sizeof(struct ocfs2_journal_lock), 0, - SLAB_NO_REAP|SLAB_HWCACHE_ALIGN, + SLAB_HWCACHE_ALIGN, NULL, NULL); if (!ocfs2_lock_cache) return -ENOMEM; @@ -1325,6 +1325,16 @@ static int ocfs2_initialize_super(struct super_block *sb, } mlog(ML_NOTICE, "max_slots for this device: %u\n", osb->max_slots); + init_waitqueue_head(&osb->osb_wipe_event); + osb->osb_orphan_wipes = kcalloc(osb->max_slots, + sizeof(*osb->osb_orphan_wipes), + GFP_KERNEL); + if (!osb->osb_orphan_wipes) { + status = -ENOMEM; + mlog_errno(status); + goto bail; + } + osb->s_feature_compat = le32_to_cpu(OCFS2_RAW_SB(di)->s_feature_compat); osb->s_feature_ro_compat = @@ -1638,6 +1648,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb) if (osb->slot_info) ocfs2_free_slot_info(osb->slot_info); + kfree(osb->osb_orphan_wipes); /* FIXME * This belongs in journal shutdown, but because we have to * allocate osb->journal at the start of ocfs2_initalize_osb(), diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index 78010ad60e4..1e4a93835fe 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -52,6 +52,7 @@ int ibm_partition(struct parsed_partitions *state, struct block_device *bdev) { int blocksize, offset, size; + loff_t i_size; dasd_information_t *info; struct hd_geometry *geo; char type[5] = {0,}; @@ -63,6 +64,13 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) unsigned char *data; Sector sect; + blocksize = bdev_hardsect_size(bdev); + if (blocksize <= 0) + return 0; + i_size = i_size_read(bdev->bd_inode); + if (i_size == 0) + return 0; + if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL) goto out_noinfo; if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL) @@ -73,9 +81,6 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 || ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0) goto out_noioctl; - - if ((blocksize = bdev_hardsect_size(bdev)) <= 0) - goto out_badsect; /* * Get volume label, extract name and type. @@ -111,7 +116,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) } else { printk("CMS1/%8s:", name); offset = (info->label_block + 1); - size = bdev->bd_inode->i_size >> 9; + size = i_size >> 9; } put_partition(state, 1, offset*(blocksize >> 9), size-offset*(blocksize >> 9)); @@ -168,7 +173,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) else printk("(nonl)/%8s:", name); offset = (info->label_block + 1); - size = (bdev->bd_inode->i_size >> 9); + size = i_size >> 9; put_partition(state, 1, offset*(blocksize >> 9), size-offset*(blocksize >> 9)); } @@ -180,7 +185,6 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) return 1; out_readerr: -out_badsect: out_noioctl: kfree(label); out_nolab: diff --git a/fs/pipe.c b/fs/pipe.c index d722579df79..8aada8e426f 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -605,7 +605,7 @@ struct file_operations rdwr_fifo_fops = { .fasync = pipe_rdwr_fasync, }; -struct file_operations read_pipe_fops = { +static struct file_operations read_pipe_fops = { .llseek = no_llseek, .read = pipe_read, .readv = pipe_readv, @@ -617,7 +617,7 @@ struct file_operations read_pipe_fops = { .fasync = pipe_read_fasync, }; -struct file_operations write_pipe_fops = { +static struct file_operations write_pipe_fops = { .llseek = no_llseek, .read = bad_pipe_r, .write = pipe_write, @@ -629,7 +629,7 @@ struct file_operations write_pipe_fops = { .fasync = pipe_write_fasync, }; -struct file_operations rdwr_pipe_fops = { +static struct file_operations rdwr_pipe_fops = { .llseek = no_llseek, .read = pipe_read, .readv = pipe_readv, diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 0eaad41f465..91b7c15ab37 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -204,7 +204,6 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, { pte_t *pte, ptent; spinlock_t *ptl; - unsigned long pfn; struct page *page; pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); @@ -214,12 +213,12 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, continue; mss->resident += PAGE_SIZE; - pfn = pte_pfn(ptent); - if (!pfn_valid(pfn)) + + page = vm_normal_page(vma, addr, ptent); + if (!page) continue; - page = pfn_to_page(pfn); - if (page_count(page) >= 2) { + if (page_mapcount(page) >= 2) { if (pte_dirty(ptent)) mss->shared_dirty += PAGE_SIZE; else @@ -289,7 +288,7 @@ static int show_smap(struct seq_file *m, void *v) struct mem_size_stats mss; memset(&mss, 0, sizeof mss); - if (vma->vm_mm) + if (vma->vm_mm && !is_vm_hugetlb_page(vma)) smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss); return show_map_internal(m, v, &mss); } diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index 3f810acd0bf..b1ca234068f 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -87,8 +87,7 @@ static int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) xpages = 1UL << order; npages = (newsize + PAGE_SIZE - 1) >> PAGE_SHIFT; - for (loop = 0; loop < npages; loop++) - set_page_count(pages + loop, 1); + split_page(pages, order); /* trim off any pages we don't actually require */ for (loop = npages; loop < xpages; loop++) diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index c66bd5e4c05..14bd2246fb6 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -27,6 +27,7 @@ #include <linux/fs.h> #include <linux/pagemap.h> #include <linux/highmem.h> +#include <linux/time.h> #include <linux/init.h> #include <linux/string.h> #include <linux/smp_lock.h> @@ -104,6 +105,7 @@ ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ error = 0; + dir->i_mtime = dir->i_ctime = CURRENT_TIME; } return error; } @@ -135,6 +137,7 @@ static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * inode->i_gid = dir->i_gid; d_instantiate(dentry, inode); dget(dentry); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; } else iput(inode); } diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index f3473176c83..be12879bb17 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -1464,13 +1464,11 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t partially overwritten pages, if needed. And lock the pages, so that nobody else can access these until we are done. We get number of actual blocks needed as a result. */ - blocks_to_allocate = - reiserfs_prepare_file_region_for_write(inode, pos, - num_pages, - write_bytes, - prepared_pages); - if (blocks_to_allocate < 0) { - res = blocks_to_allocate; + res = reiserfs_prepare_file_region_for_write(inode, pos, + num_pages, + write_bytes, + prepared_pages); + if (res < 0) { reiserfs_release_claimed_blocks(inode->i_sb, num_pages << (PAGE_CACHE_SHIFT - @@ -1478,6 +1476,8 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t break; } + blocks_to_allocate = res; + /* First we correct our estimate of how many blocks we need */ reiserfs_release_claimed_blocks(inode->i_sb, (num_pages << diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index b33d67bba2f..d60f6238c66 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -627,11 +627,6 @@ int reiserfs_get_block(struct inode *inode, sector_t block, reiserfs_write_lock(inode->i_sb); version = get_inode_item_key_version(inode); - if (block < 0) { - reiserfs_write_unlock(inode->i_sb); - return -EIO; - } - if (!file_capable(inode, block)) { reiserfs_write_unlock(inode->i_sb); return -EFBIG; @@ -934,12 +929,13 @@ int reiserfs_get_block(struct inode *inode, sector_t block, //pos_in_item * inode->i_sb->s_blocksize, TYPE_INDIRECT, 3); // key type is unimportant + RFALSE(cpu_key_k_offset(&tmp_key) > cpu_key_k_offset(&key), + "green-805: invalid offset"); blocks_needed = 1 + ((cpu_key_k_offset(&key) - cpu_key_k_offset(&tmp_key)) >> inode->i_sb-> s_blocksize_bits); - RFALSE(blocks_needed < 0, "green-805: invalid offset"); if (blocks_needed == 1) { un = &unf_single; diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index b7a179560ab..5a9d2722fa0 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2319,8 +2319,7 @@ static int journal_read(struct super_block *p_s_sb) return 1; } jh = (struct reiserfs_journal_header *)(journal->j_header_bh->b_data); - if (le32_to_cpu(jh->j_first_unflushed_offset) >= 0 && - le32_to_cpu(jh->j_first_unflushed_offset) < + if (le32_to_cpu(jh->j_first_unflushed_offset) < SB_ONDISK_JOURNAL_SIZE(p_s_sb) && le32_to_cpu(jh->j_last_flush_trans_id) > 0) { oldest_start = diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index c8123308e06..284f7852de8 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -247,7 +247,7 @@ static int linear_search_in_dir_item(struct cpu_key *key, /* mark, that this generation number is used */ if (de->de_gen_number_bit_string) set_bit(GET_GENERATION_NUMBER(deh_offset(deh)), - (unsigned long *)de->de_gen_number_bit_string); + de->de_gen_number_bit_string); // calculate pointer to name and namelen de->de_entry_num = i; @@ -431,7 +431,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th, struct reiserfs_de_head *deh; INITIALIZE_PATH(path); struct reiserfs_dir_entry de; - int bit_string[MAX_GENERATION_NUMBER / (sizeof(int) * 8) + 1]; + DECLARE_BITMAP(bit_string, MAX_GENERATION_NUMBER + 1); int gen_number; char small_buf[32 + DEH_SIZE]; /* 48 bytes now and we avoid kmalloc if we create file with short name */ @@ -486,7 +486,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th, /* find the proper place for the new entry */ memset(bit_string, 0, sizeof(bit_string)); - de.de_gen_number_bit_string = (char *)bit_string; + de.de_gen_number_bit_string = bit_string; retval = reiserfs_find_entry(dir, name, namelen, &path, &de); if (retval != NAME_NOT_FOUND) { if (buffer != small_buf) @@ -508,7 +508,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th, } gen_number = - find_first_zero_bit((unsigned long *)bit_string, + find_first_zero_bit(bit_string, MAX_GENERATION_NUMBER + 1); if (gen_number > MAX_GENERATION_NUMBER) { /* there is no free generation number */ diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 49bd219275d..9ee95686444 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -50,6 +50,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, return sd; } +/** + * + * Return -EEXIST if there is already a sysfs element with the same name for + * the same parent. + * + * called with parent inode's i_mutex held + */ +int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, + const unsigned char *new) +{ + struct sysfs_dirent * sd; + + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if (sd->s_element) { + const unsigned char *existing = sysfs_get_name(sd); + if (strcmp(existing, new)) + continue; + else + return -EEXIST; + } + } + + return 0; +} + + int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, void * element, umode_t mode, int type) { @@ -102,7 +128,11 @@ static int create_dir(struct kobject * k, struct dentry * p, mutex_lock(&p->d_inode->i_mutex); *d = lookup_one_len(n, p, strlen(n)); if (!IS_ERR(*d)) { - error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); + if (sysfs_dirent_exist(p->d_fsdata, n)) + error = -EEXIST; + else + error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, + SYSFS_DIR); if (!error) { error = sysfs_create(*d, mode, init_dir); if (!error) { @@ -302,6 +332,7 @@ void sysfs_remove_dir(struct kobject * kobj) * Drop reference from dget() on entrance. */ dput(dentry); + kobj->dentry = NULL; } int sysfs_rename_dir(struct kobject * kobj, const char *new_name) @@ -479,7 +510,3 @@ struct file_operations sysfs_dir_operations = { .read = generic_read_dir, .readdir = sysfs_readdir, }; - -EXPORT_SYMBOL_GPL(sysfs_create_dir); -EXPORT_SYMBOL_GPL(sysfs_remove_dir); -EXPORT_SYMBOL_GPL(sysfs_rename_dir); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d0e3d849516..5e83e724678 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -301,9 +301,8 @@ static int check_perm(struct inode * inode, struct file * file) /* No error? Great, allocate a buffer for the file, and store it * it in file->private_data for easy access. */ - buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL); + buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); if (buffer) { - memset(buffer,0,sizeof(struct sysfs_buffer)); init_MUTEX(&buffer->sem); buffer->needs_read_fill = 1; buffer->ops = ops; @@ -362,10 +361,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) { struct sysfs_dirent * parent_sd = dir->d_fsdata; umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; - int error = 0; + int error = -EEXIST; mutex_lock(&dir->d_inode->i_mutex); - error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type); + if (!sysfs_dirent_exist(parent_sd, attr->name)) + error = sysfs_make_dirent(parent_sd, NULL, (void *)attr, + mode, type); mutex_unlock(&dir->d_inode->i_mutex); return error; diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 689f7bcfaf3..4c29ac41ac3 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -54,11 +54,10 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) if (!sd_iattr) { /* setting attributes for the first time, allocate now */ - sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL); + sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); if (!sd_iattr) return -ENOMEM; /* assign default attributes */ - memset(sd_iattr, 0, sizeof(struct iattr)); sd_iattr->ia_mode = sd->s_mode; sd_iattr->ia_uid = 0; sd_iattr->ia_gid = 0; @@ -227,12 +226,16 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) void sysfs_hash_and_remove(struct dentry * dir, const char * name) { struct sysfs_dirent * sd; - struct sysfs_dirent * parent_sd = dir->d_fsdata; + struct sysfs_dirent * parent_sd; + + if (!dir) + return; if (dir->d_inode == NULL) /* no inode means this hasn't been made visible yet */ return; + parent_sd = dir->d_fsdata; mutex_lock(&dir->d_inode->i_mutex); list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (!sd->s_element) diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index e38d6338a20..d2eac3ceed5 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -66,6 +66,7 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj if (!error) return 0; + kobject_put(target); kfree(sl->link_name); exit2: kfree(sl); @@ -82,12 +83,13 @@ exit1: int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) { struct dentry * dentry = kobj->dentry; - int error = 0; + int error = -EEXIST; BUG_ON(!kobj || !kobj->dentry || !name); mutex_lock(&dentry->d_inode->i_mutex); - error = sysfs_add_link(dentry, name, target); + if (!sysfs_dirent_exist(dentry->d_fsdata, name)) + error = sysfs_add_link(dentry, name, target); mutex_unlock(&dentry->d_inode->i_mutex); return error; } diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3f8953e0e5d..cf11d5b789d 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -5,6 +5,7 @@ extern kmem_cache_t *sysfs_dir_cachep; extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); +extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *); extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, umode_t, int); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 395e582ee54..d04cff2273b 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1045,10 +1045,14 @@ 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 ) inode->i_uid = UDF_SB(inode->i_sb)->s_uid; + if (inode->i_uid == -1 || UDF_QUERY_FLAG(inode->i_sb, + UDF_FLAG_UID_IGNORE)) + inode->i_uid = UDF_SB(inode->i_sb)->s_uid; inode->i_gid = le32_to_cpu(fe->gid); - if ( inode->i_gid == -1 ) inode->i_gid = UDF_SB(inode->i_sb)->s_gid; + if (inode->i_gid == -1 || UDF_QUERY_FLAG(inode->i_sb, + UDF_FLAG_GID_IGNORE)) + inode->i_gid = UDF_SB(inode->i_sb)->s_gid; inode->i_nlink = le16_to_cpu(fe->fileLinkCount); if (!inode->i_nlink) @@ -1335,10 +1339,14 @@ udf_update_inode(struct inode *inode, int do_sync) return err; } - if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid) + if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET)) + fe->uid = cpu_to_le32(-1); + else if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid) fe->uid = cpu_to_le32(inode->i_uid); - if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid) + if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET)) + fe->gid = cpu_to_le32(-1); + else if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid) fe->gid = cpu_to_le32(inode->i_gid); udfperms = ((inode->i_mode & S_IRWXO) ) | diff --git a/fs/udf/super.c b/fs/udf/super.c index 4a6f49adc60..368d8f81fe5 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -269,7 +269,7 @@ enum { Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock, Opt_anchor, Opt_volume, Opt_partition, Opt_fileset, Opt_rootdir, Opt_utf8, Opt_iocharset, - Opt_err + Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore }; static match_table_t tokens = { @@ -282,6 +282,10 @@ static match_table_t tokens = { {Opt_adinicb, "adinicb"}, {Opt_shortad, "shortad"}, {Opt_longad, "longad"}, + {Opt_uforget, "uid=forget"}, + {Opt_uignore, "uid=ignore"}, + {Opt_gforget, "gid=forget"}, + {Opt_gignore, "gid=ignore"}, {Opt_gid, "gid=%u"}, {Opt_uid, "uid=%u"}, {Opt_umask, "umask=%o"}, @@ -414,6 +418,18 @@ udf_parse_options(char *options, struct udf_options *uopt) uopt->flags |= (1 << UDF_FLAG_NLS_MAP); break; #endif + case Opt_uignore: + uopt->flags |= (1 << UDF_FLAG_UID_IGNORE); + break; + case Opt_uforget: + uopt->flags |= (1 << UDF_FLAG_UID_FORGET); + break; + case Opt_gignore: + uopt->flags |= (1 << UDF_FLAG_GID_IGNORE); + break; + case Opt_gforget: + uopt->flags |= (1 << UDF_FLAG_GID_FORGET); + break; default: printk(KERN_ERR "udf: bad mount option \"%s\" " "or missing value\n", p); diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 663669810be..110f8d62616 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -20,6 +20,10 @@ #define UDF_FLAG_VARCONV 8 #define UDF_FLAG_NLS_MAP 9 #define UDF_FLAG_UTF8 10 +#define UDF_FLAG_UID_FORGET 11 /* save -1 for uid to disk */ +#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_PART_FLAG_UNALLOC_BITMAP 0x0001 #define UDF_PART_FLAG_UNALLOC_TABLE 0x0002 diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 8f2beec526c..74d8be87f98 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -540,7 +540,7 @@ xfs_probe_cluster( /* First sum forwards in this page */ do { - if (mapped != buffer_mapped(bh)) + if (!buffer_uptodate(bh) || (mapped != buffer_mapped(bh))) return total; total += bh->b_size; } while ((bh = bh->b_this_page) != head); diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index bfb4f2917bb..8cdfa415165 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -29,6 +29,7 @@ #include <linux/blkdev.h> #include <linux/hash.h> #include <linux/kthread.h> +#include <linux/migrate.h> #include "xfs_linux.h" STATIC kmem_zone_t *xfs_buf_zone; diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 53a00fb217f..7c0e39dc618 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -68,6 +68,9 @@ kmem_zone_t *qm_dqzone; kmem_zone_t *qm_dqtrxzone; STATIC kmem_shaker_t xfs_qm_shaker; +STATIC cred_t xfs_zerocr; +STATIC xfs_inode_t xfs_zeroino; + STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); @@ -1393,8 +1396,6 @@ xfs_qm_qino_alloc( xfs_trans_t *tp; int error; unsigned long s; - cred_t zerocr; - xfs_inode_t zeroino; int committed; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QINOCREATE); @@ -1406,11 +1407,9 @@ xfs_qm_qino_alloc( xfs_trans_cancel(tp, 0); return error; } - memset(&zerocr, 0, sizeof(zerocr)); - memset(&zeroino, 0, sizeof(zeroino)); - if ((error = xfs_dir_ialloc(&tp, &zeroino, S_IFREG, 1, 0, - &zerocr, 0, 1, ip, &committed))) { + if ((error = xfs_dir_ialloc(&tp, &xfs_zeroino, S_IFREG, 1, 0, + &xfs_zerocr, 0, 1, ip, &committed))) { xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); return error; diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 06fc061c50f..5b413946b1c 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -130,7 +130,8 @@ xfs_growfs_rt_alloc( /* * Lock the inode. */ - if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, &ip))) + if ((error = xfs_trans_iget(mp, tp, ino, 0, + XFS_ILOCK_EXCL, &ip))) goto error_exit; XFS_BMAP_INIT(&flist, &firstblock); /* @@ -170,8 +171,8 @@ xfs_growfs_rt_alloc( /* * Lock the bitmap inode. */ - if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, - &ip))) + if ((error = xfs_trans_iget(mp, tp, ino, 0, + XFS_ILOCK_EXCL, &ip))) goto error_exit; /* * Get a buffer for the block. @@ -2023,8 +2024,8 @@ xfs_growfs_rt( /* * Lock out other callers by grabbing the bitmap inode lock. */ - if ((error = xfs_trans_iget(mp, tp, 0, mp->m_sb.sb_rbmino, - XFS_ILOCK_EXCL, &ip))) + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, + XFS_ILOCK_EXCL, &ip))) goto error_exit; ASSERT(ip == mp->m_rbmip); /* @@ -2037,8 +2038,8 @@ xfs_growfs_rt( /* * Get the summary inode into the transaction. */ - if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, - 0, XFS_ILOCK_EXCL, &ip))) + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, + XFS_ILOCK_EXCL, &ip))) goto error_exit; ASSERT(ip == mp->m_rsumip); /* @@ -2158,10 +2159,9 @@ xfs_rtallocate_extent( /* * Lock out other callers by grabbing the bitmap inode lock. */ - error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip); - if (error) { + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, + XFS_ILOCK_EXCL, &ip))) return error; - } sumbp = NULL; /* * Allocate by size, or near another block, or exactly at some block. @@ -2221,10 +2221,9 @@ xfs_rtfree_extent( /* * Synchronize by locking the bitmap inode. */ - error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip); - if (error) { + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, + XFS_ILOCK_EXCL, &ip))) return error; - } #if defined(__KERNEL__) && defined(DEBUG) /* * Check to see that this whole range is currently allocated. @@ -2365,8 +2364,8 @@ xfs_rtpick_extent( __uint64_t seq; /* sequence number of file creation */ __uint64_t *seqp; /* pointer to seqno in inode */ - error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip); - if (error) + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, + XFS_ILOCK_EXCL, &ip))) return error; ASSERT(ip == mp->m_rbmip); seqp = (__uint64_t *)&ip->i_d.di_atime; |