aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/conv.c157
-rw-r--r--fs/9p/fid.c176
-rw-r--r--fs/9p/fid.h7
-rw-r--r--fs/9p/v9fs.c8
-rw-r--r--fs/9p/vfs_dentry.c2
-rw-r--r--fs/9p/vfs_dir.c11
-rw-r--r--fs/9p/vfs_file.c88
-rw-r--r--fs/9p/vfs_inode.c95
-rw-r--r--fs/9p/vfs_super.c39
-rw-r--r--fs/Kconfig3
-rw-r--r--fs/aio.c98
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/cifs/connect.c2
-rw-r--r--fs/eventpoll.c8
-rw-r--r--fs/ext2/ialloc.c25
-rw-r--r--fs/ext3/balloc.c6
-rw-r--r--fs/ext3/ialloc.c29
-rw-r--r--fs/ext3/resize.c6
-rw-r--r--fs/ext3/super.c11
-rw-r--r--fs/fuse/dir.c6
-rw-r--r--fs/fuse/file.c4
-rw-r--r--fs/hostfs/hostfs_kern.c7
-rw-r--r--fs/jfs/inode.c3
-rw-r--r--fs/jfs/jfs_dmap.c2
-rw-r--r--fs/jfs/jfs_txnmgr.c15
-rw-r--r--fs/jfs/jfs_txnmgr.h1
-rw-r--r--fs/nfs/read.c5
-rw-r--r--fs/ntfs/ChangeLog10
-rw-r--r--fs/ntfs/layout.h8
-rw-r--r--fs/ntfs/lcnalloc.c31
-rw-r--r--fs/ntfs/lcnalloc.h27
-rw-r--r--fs/ntfs/logfile.c30
-rw-r--r--fs/ntfs/logfile.h2
-rw-r--r--fs/ntfs/mft.c2
-rw-r--r--fs/proc/base.c8
-rw-r--r--fs/read_write.c3
36 files changed, 494 insertions, 443 deletions
diff --git a/fs/9p/conv.c b/fs/9p/conv.c
index 1554731bd65..18121af99d3 100644
--- a/fs/9p/conv.c
+++ b/fs/9p/conv.c
@@ -3,6 +3,7 @@
*
* 9P protocol conversion functions
*
+ * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
*
@@ -55,66 +56,70 @@ static inline int buf_check_overflow(struct cbuf *buf)
return buf->p > buf->ep;
}
-static inline void buf_check_size(struct cbuf *buf, int len)
+static inline int buf_check_size(struct cbuf *buf, int len)
{
if (buf->p+len > buf->ep) {
if (buf->p < buf->ep) {
eprintk(KERN_ERR, "buffer overflow\n");
buf->p = buf->ep + 1;
+ return 0;
}
}
+
+ return 1;
}
static inline void *buf_alloc(struct cbuf *buf, int len)
{
void *ret = NULL;
- buf_check_size(buf, len);
- ret = buf->p;
- buf->p += len;
+ if (buf_check_size(buf, len)) {
+ ret = buf->p;
+ buf->p += len;
+ }
return ret;
}
static inline void buf_put_int8(struct cbuf *buf, u8 val)
{
- buf_check_size(buf, 1);
-
- buf->p[0] = val;
- buf->p++;
+ if (buf_check_size(buf, 1)) {
+ buf->p[0] = val;
+ buf->p++;
+ }
}
static inline void buf_put_int16(struct cbuf *buf, u16 val)
{
- buf_check_size(buf, 2);
-
- *(__le16 *) buf->p = cpu_to_le16(val);
- buf->p += 2;
+ if (buf_check_size(buf, 2)) {
+ *(__le16 *) buf->p = cpu_to_le16(val);
+ buf->p += 2;
+ }
}
static inline void buf_put_int32(struct cbuf *buf, u32 val)
{
- buf_check_size(buf, 4);
-
- *(__le32 *)buf->p = cpu_to_le32(val);
- buf->p += 4;
+ if (buf_check_size(buf, 4)) {
+ *(__le32 *)buf->p = cpu_to_le32(val);
+ buf->p += 4;
+ }
}
static inline void buf_put_int64(struct cbuf *buf, u64 val)
{
- buf_check_size(buf, 8);
-
- *(__le64 *)buf->p = cpu_to_le64(val);
- buf->p += 8;
+ if (buf_check_size(buf, 8)) {
+ *(__le64 *)buf->p = cpu_to_le64(val);
+ buf->p += 8;
+ }
}
static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
{
- buf_check_size(buf, slen + 2);
-
- buf_put_int16(buf, slen);
- memcpy(buf->p, s, slen);
- buf->p += slen;
+ if (buf_check_size(buf, slen + 2)) {
+ buf_put_int16(buf, slen);
+ memcpy(buf->p, s, slen);
+ buf->p += slen;
+ }
}
static inline void buf_put_string(struct cbuf *buf, const char *s)
@@ -124,20 +129,20 @@ static inline void buf_put_string(struct cbuf *buf, const char *s)
static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen)
{
- buf_check_size(buf, datalen);
-
- memcpy(buf->p, data, datalen);
- buf->p += datalen;
+ if (buf_check_size(buf, datalen)) {
+ memcpy(buf->p, data, datalen);
+ buf->p += datalen;
+ }
}
static inline u8 buf_get_int8(struct cbuf *buf)
{
u8 ret = 0;
- buf_check_size(buf, 1);
- ret = buf->p[0];
-
- buf->p++;
+ if (buf_check_size(buf, 1)) {
+ ret = buf->p[0];
+ buf->p++;
+ }
return ret;
}
@@ -146,10 +151,10 @@ static inline u16 buf_get_int16(struct cbuf *buf)
{
u16 ret = 0;
- buf_check_size(buf, 2);
- ret = le16_to_cpu(*(__le16 *)buf->p);
-
- buf->p += 2;
+ if (buf_check_size(buf, 2)) {
+ ret = le16_to_cpu(*(__le16 *)buf->p);
+ buf->p += 2;
+ }
return ret;
}
@@ -158,10 +163,10 @@ static inline u32 buf_get_int32(struct cbuf *buf)
{
u32 ret = 0;
- buf_check_size(buf, 4);
- ret = le32_to_cpu(*(__le32 *)buf->p);
-
- buf->p += 4;
+ if (buf_check_size(buf, 4)) {
+ ret = le32_to_cpu(*(__le32 *)buf->p);
+ buf->p += 4;
+ }
return ret;
}
@@ -170,10 +175,10 @@ static inline u64 buf_get_int64(struct cbuf *buf)
{
u64 ret = 0;
- buf_check_size(buf, 8);
- ret = le64_to_cpu(*(__le64 *)buf->p);
-
- buf->p += 8;
+ if (buf_check_size(buf, 8)) {
+ ret = le64_to_cpu(*(__le64 *)buf->p);
+ buf->p += 8;
+ }
return ret;
}
@@ -181,27 +186,35 @@ static inline u64 buf_get_int64(struct cbuf *buf)
static inline int
buf_get_string(struct cbuf *buf, char *data, unsigned int datalen)
{
+ u16 len = 0;
+
+ len = buf_get_int16(buf);
+ if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) {
+ memcpy(data, buf->p, len);
+ data[len] = 0;
+ buf->p += len;
+ len++;
+ }
- u16 len = buf_get_int16(buf);
- buf_check_size(buf, len);
- if (len + 1 > datalen)
- return 0;
-
- memcpy(data, buf->p, len);
- data[len] = 0;
- buf->p += len;
-
- return len + 1;
+ return len;
}
static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf)
{
- char *ret = NULL;
- int n = buf_get_string(buf, sbuf->p, sbuf->ep - sbuf->p);
+ char *ret;
+ u16 len;
+
+ ret = NULL;
+ len = buf_get_int16(buf);
- if (n > 0) {
+ if (!buf_check_overflow(buf) && buf_check_size(buf, len) &&
+ buf_check_size(sbuf, len+1)) {
+
+ memcpy(sbuf->p, buf->p, len);
+ sbuf->p[len] = 0;
ret = sbuf->p;
- sbuf->p += n;
+ buf->p += len;
+ sbuf->p += len + 1;
}
return ret;
@@ -209,12 +222,15 @@ static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf)
static inline int buf_get_data(struct cbuf *buf, void *data, int datalen)
{
- buf_check_size(buf, datalen);
+ int ret = 0;
- memcpy(data, buf->p, datalen);
- buf->p += datalen;
+ if (buf_check_size(buf, datalen)) {
+ memcpy(data, buf->p, datalen);
+ buf->p += datalen;
+ ret = datalen;
+ }
- return datalen;
+ return ret;
}
static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf,
@@ -223,13 +239,12 @@ static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf,
char *ret = NULL;
int n = 0;
- buf_check_size(dbuf, datalen);
-
- n = buf_get_data(buf, dbuf->p, datalen);
-
- if (n > 0) {
- ret = dbuf->p;
- dbuf->p += n;
+ if (buf_check_size(dbuf, datalen)) {
+ n = buf_get_data(buf, dbuf->p, datalen);
+ if (n > 0) {
+ ret = dbuf->p;
+ dbuf->p += n;
+ }
}
return ret;
@@ -636,7 +651,7 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize,
break;
case RWALK:
rcall->params.rwalk.nwqid = buf_get_int16(bufp);
- rcall->params.rwalk.wqids = buf_alloc(bufp,
+ rcall->params.rwalk.wqids = buf_alloc(dbufp,
rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid));
if (rcall->params.rwalk.wqids)
for (i = 0; i < rcall->params.rwalk.nwqid; i++) {
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 821c9c4d76a..d95f8626d17 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -71,21 +71,28 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
*
*/
-struct v9fs_fid *v9fs_fid_create(struct dentry *dentry)
+struct v9fs_fid *v9fs_fid_create(struct dentry *dentry,
+ struct v9fs_session_info *v9ses, int fid, int create)
{
struct v9fs_fid *new;
+ dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n",
+ dentry, fid, create);
+
new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
if (new == NULL) {
dprintk(DEBUG_ERROR, "Out of Memory\n");
return ERR_PTR(-ENOMEM);
}
- new->fid = -1;
+ new->fid = fid;
+ new->v9ses = v9ses;
new->fidopen = 0;
- new->fidcreate = 0;
+ new->fidcreate = create;
new->fidclunked = 0;
new->iounit = 0;
+ new->rdir_pos = 0;
+ new->rdir_fcall = NULL;
if (v9fs_fid_insert(new, dentry) == 0)
return new;
@@ -109,6 +116,59 @@ 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, NULL);
+ 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)
@@ -119,49 +179,25 @@ void v9fs_fid_destroy(struct v9fs_fid *fid)
*
*/
-struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type)
+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;
- int found_parent = 0;
- int found_user = 0;
- dprintk(DEBUG_9P, " dentry: %s (%p) type %d\n", dentry->d_iname, dentry,
- type);
+ dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
- if (fid_list && !list_empty(fid_list)) {
+ if (fid_list) {
list_for_each_entry_safe(current_fid, temp, fid_list, list) {
- if (current_fid->uid == current->uid) {
- if (return_fid == NULL) {
- if ((type == FID_OP)
- || (!current_fid->fidopen)) {
- return_fid = current_fid;
- found_user = 1;
- }
- }
- }
- if (current_fid->pid == current->real_parent->pid) {
- if ((return_fid == NULL) || (found_parent)
- || (found_user)) {
- if ((type == FID_OP)
- || (!current_fid->fidopen)) {
- return_fid = current_fid;
- found_parent = 1;
- found_user = 0;
- }
- }
- }
- if (current_fid->pid == current->pid) {
- if ((type == FID_OP) ||
- (!current_fid->fidopen)) {
- return_fid = current_fid;
- found_parent = 0;
- found_user = 0;
- }
+ 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 */
@@ -187,55 +223,33 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type)
/* XXX - there may be some duplication we can get rid of */
if (par == dentry) {
- /* we need to fid_lookup the starting point */
- int fidnum = -1;
- int oldfid = -1;
- int result = -1;
- struct v9fs_session_info *v9ses =
- v9fs_inode2v9ses(current->fs->pwd->d_inode);
-
- current_fid =
- v9fs_fid_lookup(current->fs->pwd, FID_WALK);
- if (current_fid == NULL) {
- dprintk(DEBUG_ERROR,
- "process cwd doesn't have a fid\n");
- return return_fid;
- }
- oldfid = current_fid->fid;
- par = current->fs->pwd;
- /* TODO: take advantage of multiwalk */
+ return_fid = v9fs_fid_walk_up(dentry);
+ if (IS_ERR(return_fid))
+ return_fid = NULL;
+ }
+ }
- fidnum = v9fs_get_idpool(&v9ses->fidpool);
- if (fidnum < 0) {
- dprintk(DEBUG_ERROR,
- "could not get a new fid num\n");
- return return_fid;
- }
+ return return_fid;
+}
- while (par != dentry) {
- result =
- v9fs_t_walk(v9ses, oldfid, fidnum, "..",
- NULL);
- if (result < 0) {
- dprintk(DEBUG_ERROR,
- "problem walking to parent\n");
-
- break;
- }
- oldfid = fidnum;
- if (par == par->d_parent) {
- dprintk(DEBUG_ERROR,
- "can't find dentry\n");
- break;
- }
- par = par->d_parent;
- }
- if (par == dentry) {
- return_fid = v9fs_fid_create(dentry);
- return_fid->fid = fidnum;
+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;
}
}
}
- return return_fid;
+ dprintk(DEBUG_9P, "return %p\n", ret);
+ return ret;
}
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index 7db478ccca3..84c673a44c8 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -25,6 +25,7 @@
#define FID_OP 0
#define FID_WALK 1
+#define FID_CREATE 2
struct v9fs_fid {
struct list_head list; /* list of fids associated with a dentry */
@@ -52,6 +53,8 @@ struct v9fs_fid {
struct v9fs_session_info *v9ses; /* session info for this FID */
};
-struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type);
+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_fid *v9fs_fid_create(struct dentry *,
+ struct v9fs_session_info *v9ses, int fid, int create);
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 13bdbbab438..82303f3bf76 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -303,7 +303,13 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
goto SessCleanUp;
};
- v9ses->transport = trans_proto;
+ v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL);
+ if (!v9ses->transport) {
+ retval = -ENOMEM;
+ goto SessCleanUp;
+ }
+
+ memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport));
if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) {
eprintk(KERN_ERR, "problem initializing transport\n");
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index 306c96741f8..a6aa947de0f 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -67,7 +67,7 @@ static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd)
struct dentry *dc = current->fs->pwd;
dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry);
- if (v9fs_fid_lookup(dentry, FID_OP)) {
+ if (v9fs_fid_lookup(dentry)) {
dprintk(DEBUG_VFS, "VALID\n");
return 1;
}
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index c478a738418..57a43b8feef 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -197,21 +197,18 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
filemap_fdatawait(inode->i_mapping);
if (fidnum >= 0) {
- fid->fidopen--;
dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen,
fid->fid);
- if (fid->fidopen == 0) {
- if (v9fs_t_clunk(v9ses, fidnum, NULL))
- dprintk(DEBUG_ERROR, "clunk failed\n");
+ if (v9fs_t_clunk(v9ses, fidnum, NULL))
+ dprintk(DEBUG_ERROR, "clunk failed\n");
- v9fs_put_idpool(fid->fid, &v9ses->fidpool);
- }
+ v9fs_put_idpool(fid->fid, &v9ses->fidpool);
kfree(fid->rdir_fcall);
+ kfree(fid);
filp->private_data = NULL;
- v9fs_fid_destroy(fid);
}
d_drop(filp->f_dentry);
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 1f8ae7d580a..a4799e971d1 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -53,30 +53,36 @@
int v9fs_file_open(struct inode *inode, struct file *file)
{
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *v9fid = v9fs_fid_lookup(file->f_dentry, FID_WALK);
- struct v9fs_fid *v9newfid = NULL;
+ struct v9fs_fid *v9fid, *fid;
struct v9fs_fcall *fcall = NULL;
int open_mode = 0;
unsigned int iounit = 0;
int newfid = -1;
long result = -1;
- dprintk(DEBUG_VFS, "inode: %p file: %p v9fid= %p\n", inode, file,
- v9fid);
+ 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) {
- struct dentry *dentry = file->f_dentry;
dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n");
+ return -EBADF;
+ }
- /* XXX - some duplication from lookup, generalize later */
- /* basically vfs_lookup is too heavy weight */
- v9fid = v9fs_fid_lookup(file->f_dentry, FID_OP);
- if (!v9fid)
- 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;
+ }
- v9fid = v9fs_fid_lookup(dentry->d_parent, FID_WALK);
- if (!v9fid)
- return -EBADF;
+ fid->fidopen = 0;
+ fid->fidcreate = 0;
+ fid->fidclunked = 0;
+ fid->iounit = 0;
+ fid->v9ses = v9ses;
newfid = v9fs_get_idpool(&v9ses->fidpool);
if (newfid < 0) {
@@ -85,58 +91,16 @@ int v9fs_file_open(struct inode *inode, struct file *file)
}
result =
- v9fs_t_walk(v9ses, v9fid->fid, newfid,
- (char *)file->f_dentry->d_name.name, NULL);
+ v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL);
+
if (result < 0) {
v9fs_put_idpool(newfid, &v9ses->fidpool);
dprintk(DEBUG_ERROR, "rewalk didn't work\n");
return -EBADF;
}
- v9fid = v9fs_fid_create(dentry);
- if (v9fid == NULL) {
- dprintk(DEBUG_ERROR, "couldn't insert\n");
- return -ENOMEM;
- }
- v9fid->fid = newfid;
- }
-
- if (v9fid->fidcreate) {
- /* create case */
- newfid = v9fid->fid;
- iounit = v9fid->iounit;
- v9fid->fidcreate = 0;
- } else {
- if (!S_ISDIR(inode->i_mode))
- newfid = v9fid->fid;
- else {
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
- eprintk(KERN_WARNING, "allocation failed\n");
- return -ENOSPC;
- }
- /* This would be a somewhat critical clone */
- result =
- v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL,
- &fcall);
- if (result < 0) {
- dprintk(DEBUG_ERROR, "clone error: %s\n",
- FCALL_ERROR(fcall));
- kfree(fcall);
- return result;
- }
-
- v9newfid = v9fs_fid_create(file->f_dentry);
- v9newfid->fid = newfid;
- v9newfid->qid = v9fid->qid;
- v9newfid->iounit = v9fid->iounit;
- v9newfid->fidopen = 0;
- v9newfid->fidclunked = 0;
- v9newfid->v9ses = v9ses;
- v9fid = v9newfid;
- kfree(fcall);
- }
-
+ 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;
@@ -163,9 +127,13 @@ int v9fs_file_open(struct inode *inode, struct file *file)
iounit = fcall->params.ropen.iounit;
kfree(fcall);
+ } else {
+ /* create case */
+ newfid = v9fid->fid;
+ iounit = v9fid->iounit;
+ v9fid->fidcreate = 0;
}
-
file->private_data = v9fid;
v9fid->rdir_pos = 0;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 0c13fc60004..2b696ae6655 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -307,7 +307,7 @@ v9fs_create(struct inode *dir,
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, FID_WALK);
+ v9fs_fid_lookup(file_dentry->d_parent);
struct v9fs_fid *fid = NULL;
struct inode *file_inode = NULL;
struct v9fs_fcall *fcall = NULL;
@@ -317,6 +317,7 @@ v9fs_create(struct inode *dir,
long newfid = -1;
int result = 0;
unsigned int iounit = 0;
+ int wfidno = -1;
perm = unixmode2p9mode(v9ses, perm);
@@ -350,7 +351,7 @@ v9fs_create(struct inode *dir,
if (result < 0) {
dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall));
v9fs_put_idpool(newfid, &v9ses->fidpool);
- newfid = 0;
+ newfid = -1;
goto CleanUpFid;
}
@@ -369,20 +370,39 @@ v9fs_create(struct inode *dir,
qid = fcall->params.rcreate.qid;
kfree(fcall);
- fid = v9fs_fid_create(file_dentry);
+ 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;
}
- fid->fid = newfid;
- fid->fidopen = 0;
- fid->fidcreate = 1;
fid->qid = qid;
fid->iounit = iounit;
- fid->rdir_pos = 0;
- fid->rdir_fcall = NULL;
- fid->v9ses = v9ses;
+
+ /* walk to the newly created file and put the fid in the dentry */
+ wfidno = v9fs_get_idpool(&v9ses->fidpool);
+ if (newfid < 0) {
+ eprintk(KERN_WARNING, "no free fids available\n");
+ return -ENOSPC;
+ }
+
+ result = v9fs_t_walk(v9ses, dirfidnum, wfidno,
+ (char *) file_dentry->d_name.name, NULL);
+ if (result < 0) {
+ dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall));
+ v9fs_put_idpool(wfidno, &v9ses->fidpool);
+ wfidno = -1;
+ goto CleanUpFid;
+ }
+
+ if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) {
+ if (!v9fs_t_clunk(v9ses, newfid, &fcall)) {
+ v9fs_put_idpool(wfidno, &v9ses->fidpool);
+ }
+
+ goto CleanUpFid;
+ }
if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) ||
(perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) ||
@@ -410,11 +430,11 @@ v9fs_create(struct inode *dir,
d_instantiate(file_dentry, file_inode);
if (perm & V9FS_DMDIR) {
- if (v9fs_t_clunk(v9ses, newfid, &fcall))
+ if (!v9fs_t_clunk(v9ses, newfid, &fcall))
+ v9fs_put_idpool(newfid, &v9ses->fidpool);
+ else
dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n",
FCALL_ERROR(fcall));
-
- v9fs_put_idpool(newfid, &v9ses->fidpool);
kfree(fcall);
fid->fidopen = 0;
fid->fidcreate = 0;
@@ -426,12 +446,22 @@ v9fs_create(struct inode *dir,
CleanUpFid:
kfree(fcall);
- if (newfid) {
- if (v9fs_t_clunk(v9ses, newfid, &fcall))
+ if (newfid >= 0) {
+ if (!v9fs_t_clunk(v9ses, newfid, &fcall))
+ v9fs_put_idpool(newfid, &v9ses->fidpool);
+ else
+ dprintk(DEBUG_ERROR, "clunk failed: %s\n",
+ FCALL_ERROR(fcall));
+
+ kfree(fcall);
+ }
+ if (wfidno >= 0) {
+ if (!v9fs_t_clunk(v9ses, wfidno, &fcall))
+ v9fs_put_idpool(wfidno, &v9ses->fidpool);
+ else
dprintk(DEBUG_ERROR, "clunk failed: %s\n",
FCALL_ERROR(fcall));
- v9fs_put_idpool(newfid, &v9ses->fidpool);
kfree(fcall);
}
return result;
@@ -461,7 +491,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
file_inode = file->d_inode;
sb = file_inode->i_sb;
v9ses = v9fs_inode2v9ses(file_inode);
- v9fid = v9fs_fid_lookup(file, FID_OP);
+ v9fid = v9fs_fid_lookup(file);
if (!v9fid) {
dprintk(DEBUG_ERROR,
@@ -545,7 +575,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
sb = dir->i_sb;
v9ses = v9fs_inode2v9ses(dir);
- dirfid = v9fs_fid_lookup(dentry->d_parent, FID_WALK);
+ dirfid = v9fs_fid_lookup(dentry->d_parent);
if (!dirfid) {
dprintk(DEBUG_ERROR, "no dirfid\n");
@@ -573,7 +603,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
v9fs_put_idpool(newfid, &v9ses->fidpool);
if (result == -ENOENT) {
d_add(dentry, NULL);
- dprintk(DEBUG_ERROR,
+ dprintk(DEBUG_VFS,
"Return negative dentry %p count %d\n",
dentry, atomic_read(&dentry->d_count));
return NULL;
@@ -601,16 +631,13 @@ 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);
+ fid = v9fs_fid_create(dentry, v9ses, newfid, 0);
if (fid == NULL) {
dprintk(DEBUG_ERROR, "couldn't insert\n");
result = -ENOMEM;
goto FreeFcall;
}
- fid->fid = newfid;
- fid->fidopen = 0;
- fid->v9ses = v9ses;
fid->qid = fcall->params.rstat.stat->qid;
dentry->d_op = &v9fs_dentry_operations;
@@ -665,11 +692,11 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
{
struct inode *old_inode = old_dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode);
- struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_WALK);
+ struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry);
struct v9fs_fid *olddirfid =
- v9fs_fid_lookup(old_dentry->d_parent, FID_WALK);
+ v9fs_fid_lookup(old_dentry->d_parent);
struct v9fs_fid *newdirfid =
- v9fs_fid_lookup(new_dentry->d_parent, FID_WALK);
+ v9fs_fid_lookup(new_dentry->d_parent);
struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
struct v9fs_fcall *fcall = NULL;
int fid = -1;
@@ -744,7 +771,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
{
struct v9fs_fcall *fcall = NULL;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP);
+ struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
int err = -EPERM;
dprintk(DEBUG_VFS, "dentry: %p\n", dentry);
@@ -778,7 +805,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP);
+ struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
struct v9fs_fcall *fcall = NULL;
struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
int res = -EPERM;
@@ -960,7 +987,7 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
if (retval != 0)
goto FreeFcall;
- newfid = v9fs_fid_lookup(dentry, FID_OP);
+ newfid = v9fs_fid_lookup(dentry);
/* issue a twstat */
v9fs_blank_mistat(v9ses, mistat);
@@ -1004,7 +1031,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
struct v9fs_fcall *fcall = NULL;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP);
+ struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
if (!fid) {
dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n");
@@ -1063,8 +1090,8 @@ static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
int ret;
char *link = __getname();
- if (strlen(link) < buflen)
- buflen = strlen(link);
+ if (buflen > PATH_MAX)
+ buflen = PATH_MAX;
dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
@@ -1148,7 +1175,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
struct v9fs_fcall *fcall = NULL;
struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
- struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_OP);
+ struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry);
struct v9fs_fid *newfid = NULL;
char *symname = __getname();
@@ -1168,7 +1195,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
if (retval != 0)
goto FreeMem;
- newfid = v9fs_fid_lookup(dentry, FID_OP);
+ newfid = v9fs_fid_lookup(dentry);
if (!newfid) {
dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n");
goto FreeMem;
@@ -1246,7 +1273,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
if (retval != 0)
goto FreeMem;
- newfid = v9fs_fid_lookup(dentry, FID_OP);
+ newfid = v9fs_fid_lookup(dentry);
if (!newfid) {
dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n");
retval = -EINVAL;
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 868f350b2c5..82c5b008407 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -129,8 +129,7 @@ static struct super_block *v9fs_get_sb(struct file_system_type
if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
dprintk(DEBUG_ERROR, "problem initiating session\n");
- retval = newfid;
- goto free_session;
+ return ERR_PTR(newfid);
}
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
@@ -150,28 +149,24 @@ static struct super_block *v9fs_get_sb(struct file_system_type
if (!root) {
retval = -ENOMEM;
- goto release_inode;
+ goto put_back_sb;
}
sb->s_root = root;
- /* Setup the Root Inode */
- root_fid = v9fs_fid_create(root);
- if (root_fid == NULL) {
- retval = -ENOMEM;
- goto release_dentry;
- }
-
- root_fid->fidopen = 0;
- root_fid->v9ses = v9ses;
-
stat_result = v9fs_t_stat(v9ses, newfid, &fcall);
if (stat_result < 0) {
dprintk(DEBUG_ERROR, "stat error\n");
v9fs_t_clunk(v9ses, newfid, NULL);
v9fs_put_idpool(newfid, &v9ses->fidpool);
} else {
- root_fid->fid = newfid;
+ /* Setup the Root Inode */
+ root_fid = v9fs_fid_create(root, v9ses, newfid, 0);
+ if (root_fid == NULL) {
+ retval = -ENOMEM;
+ goto put_back_sb;
+ }
+
root_fid->qid = fcall->params.rstat.stat->qid;
root->d_inode->i_ino =
v9fs_qid2ino(&fcall->params.rstat.stat->qid);
@@ -182,25 +177,15 @@ static struct super_block *v9fs_get_sb(struct file_system_type
if (stat_result < 0) {
retval = stat_result;
- goto release_dentry;
+ goto put_back_sb;
}
return sb;
- release_dentry:
- dput(sb->s_root);
-
- release_inode:
- iput(inode);
-
- put_back_sb:
+put_back_sb:
+ /* deactivate_super calls v9fs_kill_super which will frees the rest */
up_write(&sb->s_umount);
deactivate_super(sb);
- v9fs_session_close(v9ses);
-
- free_session:
- kfree(v9ses);
-
return ERR_PTR(retval);
}
diff --git a/fs/Kconfig b/fs/Kconfig
index 068ccea2f18..48f5422cb19 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -472,6 +472,9 @@ config FUSE_FS
utilities is available from the FUSE homepage:
<http://fuse.sourceforge.net/>
+ See <file:Documentation/filesystems/fuse.txt> for more information.
+ See <file:Documentation/Changes> for needed library/utility version.
+
If you want to develop a userspace FS, or if you want to use
a filesystem based on FUSE, answer Y or M.
diff --git a/fs/aio.c b/fs/aio.c
index 0e11e31dbb7..d6b1551342b 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -741,19 +741,9 @@ static ssize_t aio_run_iocb(struct kiocb *iocb)
ret = retry(iocb);
current->io_wait = NULL;
- if (-EIOCBRETRY != ret) {
- if (-EIOCBQUEUED != ret) {
- BUG_ON(!list_empty(&iocb->ki_wait.task_list));
- aio_complete(iocb, ret, 0);
- /* must not access the iocb after this */
- }
- } else {
- /*
- * Issue an additional retry to avoid waiting forever if
- * no waits were queued (e.g. in case of a short read).
- */
- if (list_empty(&iocb->ki_wait.task_list))
- kiocbSetKicked(iocb);
+ if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) {
+ BUG_ON(!list_empty(&iocb->ki_wait.task_list));
+ aio_complete(iocb, ret, 0);
}
out:
spin_lock_irq(&ctx->ctx_lock);
@@ -899,16 +889,24 @@ static void aio_kick_handler(void *data)
* and if required activate the aio work queue to process
* it
*/
-static void queue_kicked_iocb(struct kiocb *iocb)
+static void try_queue_kicked_iocb(struct kiocb *iocb)
{
struct kioctx *ctx = iocb->ki_ctx;
unsigned long flags;
int run = 0;
- WARN_ON((!list_empty(&iocb->ki_wait.task_list)));
+ /* We're supposed to be the only path putting the iocb back on the run
+ * list. If we find that the iocb is *back* on a wait queue already
+ * than retry has happened before we could queue the iocb. This also
+ * means that the retry could have completed and freed our iocb, no
+ * good. */
+ BUG_ON((!list_empty(&iocb->ki_wait.task_list)));
spin_lock_irqsave(&ctx->ctx_lock, flags);
- run = __queue_kicked_iocb(iocb);
+ /* set this inside the lock so that we can't race with aio_run_iocb()
+ * testing it and putting the iocb on the run list under the lock */
+ if (!kiocbTryKick(iocb))
+ run = __queue_kicked_iocb(iocb);
spin_unlock_irqrestore(&ctx->ctx_lock, flags);
if (run)
aio_queue_work(ctx);
@@ -931,10 +929,7 @@ void fastcall kick_iocb(struct kiocb *iocb)
return;
}
- /* If its already kicked we shouldn't queue it again */
- if (!kiocbTryKick(iocb)) {
- queue_kicked_iocb(iocb);
- }
+ try_queue_kicked_iocb(iocb);
}
EXPORT_SYMBOL(kick_iocb);
@@ -1322,8 +1317,11 @@ asmlinkage long sys_io_destroy(aio_context_t ctx)
}
/*
- * Default retry method for aio_read (also used for first time submit)
- * Responsible for updating iocb state as retries progress
+ * aio_p{read,write} are the default ki_retry methods for
+ * IO_CMD_P{READ,WRITE}. They maintains kiocb retry state around potentially
+ * multiple calls to f_op->aio_read(). They loop around partial progress
+ * instead of returning -EIOCBRETRY because they don't have the means to call
+ * kick_iocb().
*/
static ssize_t aio_pread(struct kiocb *iocb)
{
@@ -1332,25 +1330,25 @@ static ssize_t aio_pread(struct kiocb *iocb)
struct inode *inode = mapping->host;
ssize_t ret = 0;
- ret = file->f_op->aio_read(iocb, iocb->ki_buf,
- iocb->ki_left, iocb->ki_pos);
+ do {
+ ret = file->f_op->aio_read(iocb, iocb->ki_buf,
+ iocb->ki_left, iocb->ki_pos);
+ /*
+ * Can't just depend on iocb->ki_left to determine
+ * whether we are done. This may have been a short read.
+ */
+ if (ret > 0) {
+ iocb->ki_buf += ret;
+ iocb->ki_left -= ret;
+ }
- /*
- * Can't just depend on iocb->ki_left to determine
- * whether we are done. This may have been a short read.
- */
- if (ret > 0) {
- iocb->ki_buf += ret;
- iocb->ki_left -= ret;
/*
- * For pipes and sockets we return once we have
- * some data; for regular files we retry till we
- * complete the entire read or find that we can't
- * read any more data (e.g short reads).
+ * For pipes and sockets we return once we have some data; for
+ * regular files we retry till we complete the entire read or
+ * find that we can't read any more data (e.g short reads).
*/
- if (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode))
- ret = -EIOCBRETRY;
- }
+ } while (ret > 0 && iocb->ki_left > 0 &&
+ !S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode));
/* This means we must have transferred all that we could */
/* No need to retry anymore */
@@ -1360,27 +1358,21 @@ static ssize_t aio_pread(struct kiocb *iocb)
return ret;
}
-/*
- * Default retry method for aio_write (also used for first time submit)
- * Responsible for updating iocb state as retries progress
- */
+/* see aio_pread() */
static ssize_t aio_pwrite(struct kiocb *iocb)
{
struct file *file = iocb->ki_filp;
ssize_t ret = 0;
- ret = file->f_op->aio_write(iocb, iocb->ki_buf,
- iocb->ki_left, iocb->ki_pos);
-
- if (ret > 0) {
- iocb->ki_buf += ret;
- iocb->ki_left -= ret;
-
- ret = -EIOCBRETRY;
- }
+ do {
+ ret = file->f_op->aio_write(iocb, iocb->ki_buf,
+ iocb->ki_left, iocb->ki_pos);
+ if (ret > 0) {
+ iocb->ki_buf += ret;
+ iocb->ki_left -= ret;
+ }
+ } while (ret > 0 && iocb->ki_left > 0);
- /* This means we must have transferred all that we could */
- /* No need to retry anymore */
if ((ret == 0) || (iocb->ki_left == 0))
ret = iocb->ki_nbytes - iocb->ki_left;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 8cc23e7d0d5..1ebf7dafc1d 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -781,6 +781,8 @@ static int cifs_oplock_thread(void * dummyarg)
oplockThread = current;
do {
+ if (try_to_freeze())
+ continue;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1*HZ);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 2335f14a158..47360156cc5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -344,6 +344,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
while (server->tcpStatus != CifsExiting) {
+ if (try_to_freeze())
+ continue;
if (bigbuf == NULL) {
bigbuf = cifs_buf_get();
if(bigbuf == NULL) {
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 403b90a1213..4284cd31eba 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -101,6 +101,10 @@
/* Maximum number of poll wake up nests we are allowing */
#define EP_MAX_POLLWAKE_NESTS 4
+/* Maximum msec timeout value storeable in a long int */
+#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
+
+
struct epoll_filefd {
struct file *file;
int fd;
@@ -1506,8 +1510,8 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
* and the overflow condition. The passed timeout is in milliseconds,
* that why (t * HZ) / 1000.
*/
- jtimeout = timeout == -1 || timeout > (MAX_SCHEDULE_TIMEOUT - 1000) / HZ ?
- MAX_SCHEDULE_TIMEOUT: (timeout * HZ + 999) / 1000;
+ jtimeout = (timeout < 0 || timeout >= EP_MAX_MSTIMEO) ?
+ MAX_SCHEDULE_TIMEOUT : (timeout * HZ + 999) / 1000;
retry:
write_lock_irqsave(&ep->lock, flags);
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index c8d07030c89..e2d6208633a 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -605,27 +605,28 @@ got:
insert_inode_hash(inode);
if (DQUOT_ALLOC_INODE(inode)) {
- DQUOT_DROP(inode);
err = -ENOSPC;
- goto fail2;
+ goto fail_drop;
}
+
err = ext2_init_acl(inode, dir);
- if (err) {
- DQUOT_FREE_INODE(inode);
- DQUOT_DROP(inode);
- goto fail2;
- }
+ if (err)
+ goto fail_free_drop;
+
err = ext2_init_security(inode,dir);
- if (err) {
- DQUOT_FREE_INODE(inode);
- goto fail2;
- }
+ if (err)
+ goto fail_free_drop;
+
mark_inode_dirty(inode);
ext2_debug("allocating inode %lu\n", inode->i_ino);
ext2_preread_inode(inode);
return inode;
-fail2:
+fail_free_drop:
+ DQUOT_FREE_INODE(inode);
+
+fail_drop:
+ DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index e463dca008e..0213db4911a 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1410,7 +1410,7 @@ unsigned long ext3_count_free_blocks(struct super_block *sb)
unsigned long desc_count;
struct ext3_group_desc *gdp;
int i;
- unsigned long ngroups;
+ unsigned long ngroups = EXT3_SB(sb)->s_groups_count;
#ifdef EXT3FS_DEBUG
struct ext3_super_block *es;
unsigned long bitmap_count, x;
@@ -1421,7 +1421,8 @@ unsigned long ext3_count_free_blocks(struct super_block *sb)
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
- for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
+
+ for (i = 0; i < ngroups; i++) {
gdp = ext3_get_group_desc(sb, i, NULL);
if (!gdp)
continue;
@@ -1443,7 +1444,6 @@ unsigned long ext3_count_free_blocks(struct super_block *sb)
return bitmap_count;
#else
desc_count = 0;
- ngroups = EXT3_SB(sb)->s_groups_count;
smp_rmb();
for (i = 0; i < ngroups; i++) {
gdp = ext3_get_group_desc(sb, i, NULL);
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 96552769d03..6549945f9ac 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -597,27 +597,22 @@ got:
ret = inode;
if(DQUOT_ALLOC_INODE(inode)) {
- DQUOT_DROP(inode);
err = -EDQUOT;
- goto fail2;
+ goto fail_drop;
}
+
err = ext3_init_acl(handle, inode, dir);
- if (err) {
- DQUOT_FREE_INODE(inode);
- DQUOT_DROP(inode);
- goto fail2;
- }
+ if (err)
+ goto fail_free_drop;
+
err = ext3_init_security(handle,inode, dir);
- if (err) {
- DQUOT_FREE_INODE(inode);
- goto fail2;
- }
+ if (err)
+ goto fail_free_drop;
+
err = ext3_mark_inode_dirty(handle, inode);
if (err) {
ext3_std_error(sb, err);
- DQUOT_FREE_INODE(inode);
- DQUOT_DROP(inode);
- goto fail2;
+ goto fail_free_drop;
}
ext3_debug("allocating inode %lu\n", inode->i_ino);
@@ -631,7 +626,11 @@ really_out:
brelse(bitmap_bh);
return ret;
-fail2:
+fail_free_drop:
+ DQUOT_FREE_INODE(inode);
+
+fail_drop:
+ DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 2c9f81278d5..57f79106267 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -242,7 +242,7 @@ static int setup_new_group_blocks(struct super_block *sb,
i < sbi->s_itb_per_group; i++, bit++, block++) {
struct buffer_head *it;
- ext3_debug("clear inode block %#04x (+%ld)\n", block, bit);
+ ext3_debug("clear inode block %#04lx (+%d)\n", block, bit);
if (IS_ERR(it = bclean(handle, sb, block))) {
err = PTR_ERR(it);
goto exit_bh;
@@ -643,8 +643,8 @@ static void update_backups(struct super_block *sb,
break;
bh = sb_getblk(sb, group * bpg + blk_off);
- ext3_debug(sb, __FUNCTION__, "update metadata backup %#04lx\n",
- bh->b_blocknr);
+ ext3_debug("update metadata backup %#04lx\n",
+ (unsigned long)bh->b_blocknr);
if ((err = ext3_journal_get_write_access(handle, bh)))
break;
lock_buffer(bh);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index a93c3609025..9e24ceb019f 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -512,15 +512,14 @@ static void ext3_clear_inode(struct inode *inode)
static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
- struct ext3_sb_info *sbi = EXT3_SB(vfs->mnt_sb);
+ struct super_block *sb = vfs->mnt_sb;
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
- if (sbi->s_mount_opt & EXT3_MOUNT_JOURNAL_DATA)
+ if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA)
seq_puts(seq, ",data=journal");
-
- if (sbi->s_mount_opt & EXT3_MOUNT_ORDERED_DATA)
+ else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA)
seq_puts(seq, ",data=ordered");
-
- if (sbi->s_mount_opt & EXT3_MOUNT_WRITEBACK_DATA)
+ else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
seq_puts(seq, ",data=writeback");
#if defined(CONFIG_QUOTA)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index e79e49b3eec..29f1e9f6e85 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -96,6 +96,8 @@ static int fuse_lookup_iget(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 || outarg.nodeid == FUSE_ROOT_ID))
+ err = -EIO;
if (!err) {
inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
&outarg.attr);
@@ -152,6 +154,10 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
fuse_put_request(fc, req);
return err;
}
+ if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
+ fuse_put_request(fc, req);
+ return -EIO;
+ }
inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
&outarg.attr);
if (!inode) {
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 6454022b053..657ab11c173 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -23,6 +23,10 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
struct fuse_file *ff;
int err;
+ /* VFS checks this, but only _after_ ->open() */
+ if (file->f_flags & O_DIRECT)
+ return -EINVAL;
+
err = generic_file_open(inode, file);
if (err)
return err;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 59c5062cd63..dd711310626 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -793,11 +793,6 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
return(err);
}
-void hostfs_truncate(struct inode *ino)
-{
- not_implemented();
-}
-
int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
{
char *name;
@@ -894,7 +889,6 @@ static struct inode_operations hostfs_iops = {
.rmdir = hostfs_rmdir,
.mknod = hostfs_mknod,
.rename = hostfs_rename,
- .truncate = hostfs_truncate,
.permission = hostfs_permission,
.setattr = hostfs_setattr,
.getattr = hostfs_getattr,
@@ -910,7 +904,6 @@ static struct inode_operations hostfs_dir_iops = {
.rmdir = hostfs_rmdir,
.mknod = hostfs_mknod,
.rename = hostfs_rename,
- .truncate = hostfs_truncate,
.permission = hostfs_permission,
.setattr = hostfs_setattr,
.getattr = hostfs_getattr,
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 0ec62d5310d..9f942ca8e4e 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -129,8 +129,7 @@ void jfs_delete_inode(struct inode *inode)
jfs_info("In jfs_delete_inode, inode = 0x%p", inode);
if (!is_bad_inode(inode) &&
- (JFS_IP(inode)->fileset == cpu_to_le32(FILESYSTEM_I))) {
-
+ (JFS_IP(inode)->fileset == FILESYSTEM_I)) {
truncate_inode_pages(&inode->i_data, 0);
if (test_cflag(COMMIT_Freewmap, inode))
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index c739626f5bf..eadf319bee2 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -3055,7 +3055,7 @@ static int cntlz(u32 value)
* RETURN VALUES:
* log2 number of blocks
*/
-int blkstol2(s64 nb)
+static int blkstol2(s64 nb)
{
int l2nb;
s64 mask; /* meant to be signed */
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index c7a92f9deb2..9b71ed2674f 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -725,6 +725,9 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
else
tlck->flag = tlckINODELOCK;
+ if (S_ISDIR(ip->i_mode))
+ tlck->flag |= tlckDIRECTORY;
+
tlck->type = 0;
/* bind the tlock and the page */
@@ -1009,6 +1012,8 @@ struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
/* bind the tlock and the object */
tlck->flag = tlckINODELOCK;
+ if (S_ISDIR(ip->i_mode))
+ tlck->flag |= tlckDIRECTORY;
tlck->ip = ip;
tlck->mp = NULL;
@@ -1077,6 +1082,8 @@ struct linelock *txLinelock(struct linelock * tlock)
linelock->flag = tlckLINELOCK;
linelock->maxcnt = TLOCKLONG;
linelock->index = 0;
+ if (tlck->flag & tlckDIRECTORY)
+ linelock->flag |= tlckDIRECTORY;
/* append linelock after tlock */
linelock->next = tlock->next;
@@ -2070,8 +2077,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
*
* function: log from maplock of freed data extents;
*/
-void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
- struct tlock * tlck)
+static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+ struct tlock * tlck)
{
struct pxd_lock *pxdlock;
int i, nlock;
@@ -2209,7 +2216,7 @@ void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea)
* function: synchronously write pages locked by transaction
* after txLog() but before txUpdateMap();
*/
-void txForce(struct tblock * tblk)
+static void txForce(struct tblock * tblk)
{
struct tlock *tlck;
lid_t lid, next;
@@ -2358,7 +2365,7 @@ static void txUpdateMap(struct tblock * tblk)
*/
else { /* (maplock->flag & mlckFREE) */
- if (S_ISDIR(tlck->ip->i_mode))
+ if (tlck->flag & tlckDIRECTORY)
txFreeMap(ipimap, maplock,
tblk, COMMIT_PWMAP);
else
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
index 59ad0f6b723..0e4dc4514c4 100644
--- a/fs/jfs/jfs_txnmgr.h
+++ b/fs/jfs/jfs_txnmgr.h
@@ -122,6 +122,7 @@ extern struct tlock *TxLock; /* transaction lock table */
#define tlckLOG 0x0800
/* updateMap state */
#define tlckUPDATEMAP 0x0080
+#define tlckDIRECTORY 0x0040
/* freeLock state */
#define tlckFREELOCK 0x0008
#define tlckWRITEPAGE 0x0004
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 6ceb1d471f2..9758ebd4990 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -184,14 +184,13 @@ static void nfs_readpage_release(struct nfs_page *req)
{
unlock_page(req->wb_page);
- nfs_clear_request(req);
- nfs_release_request(req);
-
dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
req->wb_context->dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_context->dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
+ nfs_clear_request(req);
+ nfs_release_request(req);
}
/*
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index c7e9237379c..83f3322765c 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -29,7 +29,8 @@ ToDo/Notes:
The Windows boot will run chkdsk and then reboot. The user can then
immediately boot into Linux rather than having to do a full Windows
boot first before rebooting into Linux and we will recognize such a
- journal and empty it as it is clean by definition.
+ journal and empty it as it is clean by definition. Note, this only
+ works if chkdsk left the journal in an obviously clean state.
- Support journals ($LogFile) with only one restart page as well as
journals with two different restart pages. We sanity check both and
either use the only sane one or the more recent one of the two in the
@@ -94,6 +95,13 @@ ToDo/Notes:
my ways.
- Fix various bugs in the runlist merging code. (Based on libntfs
changes by Richard Russon.)
+ - Fix sparse warnings that have crept in over time.
+ - Change ntfs_cluster_free() to require a write locked runlist on entry
+ since we otherwise get into a lock reversal deadlock if a read locked
+ runlist is passed in. In the process also change it to take an ntfs
+ inode instead of a vfs inode as parameter.
+ - Fix the definition of the CHKD ntfs record magic. It had an off by
+ two error causing it to be CHKB instead of CHKD.
2.1.23 - Implement extension of resident files and make writing safe as well as
many bug fixes, cleanups, and enhancements...
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h
index 609ad1728ce..01f2dfa39ce 100644
--- a/fs/ntfs/layout.h
+++ b/fs/ntfs/layout.h
@@ -123,7 +123,7 @@ enum {
magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */
/* Found in $LogFile/$DATA. (May be found in $MFT/$DATA, also?) */
- magic_CHKD = const_cpu_to_le32(0x424b4843), /* Modified by chkdsk. */
+ magic_CHKD = const_cpu_to_le32(0x444b4843), /* Modified by chkdsk. */
/* Found in all ntfs record containing records. */
magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector
@@ -308,10 +308,8 @@ typedef le16 MFT_RECORD_FLAGS;
* The _LE versions are to be applied on little endian MFT_REFs.
* Note: The _LE versions will return a CPU endian formatted value!
*/
-typedef enum {
- MFT_REF_MASK_CPU = 0x0000ffffffffffffULL,
- MFT_REF_MASK_LE = const_cpu_to_le64(0x0000ffffffffffffULL),
-} MFT_REF_CONSTS;
+#define MFT_REF_MASK_CPU 0x0000ffffffffffffULL
+#define MFT_REF_MASK_LE const_cpu_to_le64(0x0000ffffffffffffULL)
typedef u64 MFT_REF;
typedef le64 leMFT_REF;
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c
index 7b593429068..5af3bf0b7ee 100644
--- a/fs/ntfs/lcnalloc.c
+++ b/fs/ntfs/lcnalloc.c
@@ -779,14 +779,13 @@ out:
/**
* __ntfs_cluster_free - free clusters on an ntfs volume
- * @vi: vfs inode whose runlist describes the clusters to free
- * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters
+ * @ni: ntfs inode whose runlist describes the clusters to free
+ * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters
* @count: number of clusters to free or -1 for all clusters
- * @write_locked: true if the runlist is locked for writing
* @is_rollback: true if this is a rollback operation
*
* Free @count clusters starting at the cluster @start_vcn in the runlist
- * described by the vfs inode @vi.
+ * described by the vfs inode @ni.
*
* If @count is -1, all clusters from @start_vcn to the end of the runlist are
* deallocated. Thus, to completely free all clusters in a runlist, use
@@ -801,31 +800,28 @@ out:
* Return the number of deallocated clusters (not counting sparse ones) on
* success and -errno on error.
*
- * Locking: - The runlist described by @vi must be locked on entry and is
- * locked on return. Note if the runlist is locked for reading the
- * lock may be dropped and reacquired. Note the runlist may be
- * modified when needed runlist fragments need to be mapped.
+ * Locking: - The runlist described by @ni must be locked for writing on entry
+ * and is locked on return. Note the runlist may be modified when
+ * needed runlist fragments need to be mapped.
* - The volume lcn bitmap must be unlocked on entry and is unlocked
* on return.
* - This function takes the volume lcn bitmap lock for writing and
* modifies the bitmap contents.
*/
-s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
- const BOOL write_locked, const BOOL is_rollback)
+s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count,
+ const BOOL is_rollback)
{
s64 delta, to_free, total_freed, real_freed;
- ntfs_inode *ni;
ntfs_volume *vol;
struct inode *lcnbmp_vi;
runlist_element *rl;
int err;
- BUG_ON(!vi);
+ BUG_ON(!ni);
ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count "
- "0x%llx.%s", vi->i_ino, (unsigned long long)start_vcn,
+ "0x%llx.%s", ni->mft_no, (unsigned long long)start_vcn,
(unsigned long long)count,
is_rollback ? " (rollback)" : "");
- ni = NTFS_I(vi);
vol = ni->vol;
lcnbmp_vi = vol->lcnbmp_ino;
BUG_ON(!lcnbmp_vi);
@@ -843,7 +839,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
total_freed = real_freed = 0;
- rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, write_locked);
+ rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, TRUE);
if (IS_ERR(rl)) {
if (!is_rollback)
ntfs_error(vol->sb, "Failed to find first runlist "
@@ -897,7 +893,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
/* Attempt to map runlist. */
vcn = rl->vcn;
- rl = ntfs_attr_find_vcn_nolock(ni, vcn, write_locked);
+ rl = ntfs_attr_find_vcn_nolock(ni, vcn, TRUE);
if (IS_ERR(rl)) {
err = PTR_ERR(rl);
if (!is_rollback)
@@ -965,8 +961,7 @@ err_out:
* If rollback fails, set the volume errors flag, emit an error
* message, and return the error code.
*/
- delta = __ntfs_cluster_free(vi, start_vcn, total_freed, write_locked,
- TRUE);
+ delta = __ntfs_cluster_free(ni, start_vcn, total_freed, TRUE);
if (delta < 0) {
ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving "
"inconsistent metadata! Unmount and run "
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h
index e4d7fb98d68..a6a8827882e 100644
--- a/fs/ntfs/lcnalloc.h
+++ b/fs/ntfs/lcnalloc.h
@@ -2,7 +2,7 @@
* lcnalloc.h - Exports for NTFS kernel cluster (de)allocation. Part of the
* Linux-NTFS project.
*
- * Copyright (c) 2004 Anton Altaparmakov
+ * Copyright (c) 2004-2005 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@@ -28,6 +28,7 @@
#include <linux/fs.h>
#include "types.h"
+#include "inode.h"
#include "runlist.h"
#include "volume.h"
@@ -42,18 +43,17 @@ extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol,
const VCN start_vcn, const s64 count, const LCN start_lcn,
const NTFS_CLUSTER_ALLOCATION_ZONES zone);
-extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
- s64 count, const BOOL write_locked, const BOOL is_rollback);
+extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
+ s64 count, const BOOL is_rollback);
/**
* ntfs_cluster_free - free clusters on an ntfs volume
- * @vi: vfs inode whose runlist describes the clusters to free
- * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters
+ * @ni: ntfs inode whose runlist describes the clusters to free
+ * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters
* @count: number of clusters to free or -1 for all clusters
- * @write_locked: true if the runlist is locked for writing
*
* Free @count clusters starting at the cluster @start_vcn in the runlist
- * described by the vfs inode @vi.
+ * described by the ntfs inode @ni.
*
* If @count is -1, all clusters from @start_vcn to the end of the runlist are
* deallocated. Thus, to completely free all clusters in a runlist, use
@@ -65,19 +65,18 @@ extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
* Return the number of deallocated clusters (not counting sparse ones) on
* success and -errno on error.
*
- * Locking: - The runlist described by @vi must be locked on entry and is
- * locked on return. Note if the runlist is locked for reading the
- * lock may be dropped and reacquired. Note the runlist may be
- * modified when needed runlist fragments need to be mapped.
+ * Locking: - The runlist described by @ni must be locked for writing on entry
+ * and is locked on return. Note the runlist may be modified when
+ * needed runlist fragments need to be mapped.
* - The volume lcn bitmap must be unlocked on entry and is unlocked
* on return.
* - This function takes the volume lcn bitmap lock for writing and
* modifies the bitmap contents.
*/
-static inline s64 ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
- s64 count, const BOOL write_locked)
+static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
+ s64 count)
{
- return __ntfs_cluster_free(vi, start_vcn, count, write_locked, FALSE);
+ return __ntfs_cluster_free(ni, start_vcn, count, FALSE);
}
extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
index 0173e95500d..0fd70295cca 100644
--- a/fs/ntfs/logfile.c
+++ b/fs/ntfs/logfile.c
@@ -51,7 +51,8 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
RESTART_PAGE_HEADER *rp, s64 pos)
{
u32 logfile_system_page_size, logfile_log_page_size;
- u16 usa_count, usa_ofs, usa_end, ra_ofs;
+ u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
+ BOOL have_usa = TRUE;
ntfs_debug("Entering.");
/*
@@ -86,6 +87,14 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
(int)sle16_to_cpu(rp->minor_ver));
return FALSE;
}
+ /*
+ * If chkdsk has been run the restart page may not be protected by an
+ * update sequence array.
+ */
+ if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
+ have_usa = FALSE;
+ goto skip_usa_checks;
+ }
/* Verify the size of the update sequence array. */
usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
if (usa_count != le16_to_cpu(rp->usa_count)) {
@@ -102,6 +111,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
"inconsistent update sequence array offset.");
return FALSE;
}
+skip_usa_checks:
/*
* Verify the position of the restart area. It must be:
* - aligned to 8-byte boundary,
@@ -109,7 +119,8 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
* - within the system page size.
*/
ra_ofs = le16_to_cpu(rp->restart_area_offset);
- if (ra_ofs & 7 || ra_ofs < usa_end ||
+ if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
+ ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
ra_ofs > logfile_system_page_size) {
ntfs_error(vi->i_sb, "$LogFile restart page specifies "
"inconsistent restart area offset.");
@@ -402,8 +413,12 @@ static int ntfs_check_and_load_restart_page(struct inode *vi,
idx++;
} while (to_read > 0);
}
- /* Perform the multi sector transfer deprotection on the buffer. */
- if (post_read_mst_fixup((NTFS_RECORD*)trp,
+ /*
+ * Perform the multi sector transfer deprotection on the buffer if the
+ * restart page is protected.
+ */
+ if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
+ && post_read_mst_fixup((NTFS_RECORD*)trp,
le32_to_cpu(rp->system_page_size))) {
/*
* A multi sector tranfer error was detected. We only need to
@@ -615,11 +630,16 @@ is_empty:
* Otherwise just throw it away.
*/
if (rstr2_lsn > rstr1_lsn) {
+ ntfs_debug("Using second restart page as it is more "
+ "recent.");
ntfs_free(rstr1_ph);
rstr1_ph = rstr2_ph;
/* rstr1_lsn = rstr2_lsn; */
- } else
+ } else {
+ ntfs_debug("Using first restart page as it is more "
+ "recent.");
ntfs_free(rstr2_ph);
+ }
rstr2_ph = NULL;
}
/* All consistency checks passed. */
diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h
index 42388f95ea6..a51f3dd0e9e 100644
--- a/fs/ntfs/logfile.h
+++ b/fs/ntfs/logfile.h
@@ -113,7 +113,7 @@ typedef struct {
*/
enum {
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002),
- RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
+ RESTART_SPACE_FILLER = const_cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */
} __attribute__ ((__packed__));
typedef le16 RESTART_AREA_FLAGS;
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 2c32b84385a..247586d1d5d 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -1953,7 +1953,7 @@ restore_undo_alloc:
a = ctx->attr;
a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1);
undo_alloc:
- if (ntfs_cluster_free(vol->mft_ino, old_last_vcn, -1, TRUE) < 0) {
+ if (ntfs_cluster_free(mft_ni, old_last_vcn, -1) < 0) {
ntfs_error(vol->sb, "Failed to free clusters from mft data "
"attribute.%s", es);
NVolSetErrors(vol);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index fb34f88a4a7..3b33f94020d 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -343,7 +343,8 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
/* Same as proc_root_link, but this addionally tries to get fs from other
* threads in the group */
-static int proc_task_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+static int proc_task_root_link(struct inode *inode, struct dentry **dentry,
+ struct vfsmount **mnt)
{
struct fs_struct *fs;
int result = -ENOENT;
@@ -357,9 +358,10 @@ static int proc_task_root_link(struct inode *inode, struct dentry **dentry, stru
} else {
/* Try to get fs from other threads */
task_unlock(leader);
- struct task_struct *task = leader;
read_lock(&tasklist_lock);
- if (pid_alive(task)) {
+ if (pid_alive(leader)) {
+ struct task_struct *task = leader;
+
while ((task = next_thread(task)) != leader) {
task_lock(task);
fs = task->fs;
diff --git a/fs/read_write.c b/fs/read_write.c
index b60324aaa2b..a091ee4f430 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -499,6 +499,9 @@ static ssize_t do_readv_writev(int type, struct file *file,
ret = rw_verify_area(type, file, pos, tot_len);
if (ret)
goto out;
+ ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
+ if (ret)
+ goto out;
fnv = NULL;
if (type == READ) {