diff options
Diffstat (limited to 'fs')
54 files changed, 939 insertions, 758 deletions
diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 1554731bd653..18121af99d3e 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * 9P protocol conversion functions | 4 | * 9P protocol conversion functions |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net> | ||
| 6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | 7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
| 7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | 8 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> |
| 8 | * | 9 | * |
| @@ -55,66 +56,70 @@ static inline int buf_check_overflow(struct cbuf *buf) | |||
| 55 | return buf->p > buf->ep; | 56 | return buf->p > buf->ep; |
| 56 | } | 57 | } |
| 57 | 58 | ||
| 58 | static inline void buf_check_size(struct cbuf *buf, int len) | 59 | static inline int buf_check_size(struct cbuf *buf, int len) |
| 59 | { | 60 | { |
| 60 | if (buf->p+len > buf->ep) { | 61 | if (buf->p+len > buf->ep) { |
| 61 | if (buf->p < buf->ep) { | 62 | if (buf->p < buf->ep) { |
| 62 | eprintk(KERN_ERR, "buffer overflow\n"); | 63 | eprintk(KERN_ERR, "buffer overflow\n"); |
| 63 | buf->p = buf->ep + 1; | 64 | buf->p = buf->ep + 1; |
| 65 | return 0; | ||
| 64 | } | 66 | } |
| 65 | } | 67 | } |
| 68 | |||
| 69 | return 1; | ||
| 66 | } | 70 | } |
| 67 | 71 | ||
| 68 | static inline void *buf_alloc(struct cbuf *buf, int len) | 72 | static inline void *buf_alloc(struct cbuf *buf, int len) |
| 69 | { | 73 | { |
| 70 | void *ret = NULL; | 74 | void *ret = NULL; |
| 71 | 75 | ||
| 72 | buf_check_size(buf, len); | 76 | if (buf_check_size(buf, len)) { |
| 73 | ret = buf->p; | 77 | ret = buf->p; |
| 74 | buf->p += len; | 78 | buf->p += len; |
| 79 | } | ||
| 75 | 80 | ||
| 76 | return ret; | 81 | return ret; |
| 77 | } | 82 | } |
| 78 | 83 | ||
| 79 | static inline void buf_put_int8(struct cbuf *buf, u8 val) | 84 | static inline void buf_put_int8(struct cbuf *buf, u8 val) |
| 80 | { | 85 | { |
| 81 | buf_check_size(buf, 1); | 86 | if (buf_check_size(buf, 1)) { |
| 82 | 87 | buf->p[0] = val; | |
| 83 | buf->p[0] = val; | 88 | buf->p++; |
| 84 | buf->p++; | 89 | } |
| 85 | } | 90 | } |
| 86 | 91 | ||
| 87 | static inline void buf_put_int16(struct cbuf *buf, u16 val) | 92 | static inline void buf_put_int16(struct cbuf *buf, u16 val) |
| 88 | { | 93 | { |
| 89 | buf_check_size(buf, 2); | 94 | if (buf_check_size(buf, 2)) { |
| 90 | 95 | *(__le16 *) buf->p = cpu_to_le16(val); | |
| 91 | *(__le16 *) buf->p = cpu_to_le16(val); | 96 | buf->p += 2; |
| 92 | buf->p += 2; | 97 | } |
| 93 | } | 98 | } |
| 94 | 99 | ||
| 95 | static inline void buf_put_int32(struct cbuf *buf, u32 val) | 100 | static inline void buf_put_int32(struct cbuf *buf, u32 val) |
| 96 | { | 101 | { |
| 97 | buf_check_size(buf, 4); | 102 | if (buf_check_size(buf, 4)) { |
| 98 | 103 | *(__le32 *)buf->p = cpu_to_le32(val); | |
| 99 | *(__le32 *)buf->p = cpu_to_le32(val); | 104 | buf->p += 4; |
| 100 | buf->p += 4; | 105 | } |
| 101 | } | 106 | } |
| 102 | 107 | ||
| 103 | static inline void buf_put_int64(struct cbuf *buf, u64 val) | 108 | static inline void buf_put_int64(struct cbuf *buf, u64 val) |
| 104 | { | 109 | { |
| 105 | buf_check_size(buf, 8); | 110 | if (buf_check_size(buf, 8)) { |
| 106 | 111 | *(__le64 *)buf->p = cpu_to_le64(val); | |
| 107 | *(__le64 *)buf->p = cpu_to_le64(val); | 112 | buf->p += 8; |
| 108 | buf->p += 8; | 113 | } |
| 109 | } | 114 | } |
| 110 | 115 | ||
| 111 | static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) | 116 | static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) |
| 112 | { | 117 | { |
| 113 | buf_check_size(buf, slen + 2); | 118 | if (buf_check_size(buf, slen + 2)) { |
| 114 | 119 | buf_put_int16(buf, slen); | |
| 115 | buf_put_int16(buf, slen); | 120 | memcpy(buf->p, s, slen); |
| 116 | memcpy(buf->p, s, slen); | 121 | buf->p += slen; |
| 117 | buf->p += slen; | 122 | } |
| 118 | } | 123 | } |
| 119 | 124 | ||
| 120 | static inline void buf_put_string(struct cbuf *buf, const char *s) | 125 | 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) | |||
| 124 | 129 | ||
| 125 | static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) | 130 | static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) |
| 126 | { | 131 | { |
| 127 | buf_check_size(buf, datalen); | 132 | if (buf_check_size(buf, datalen)) { |
| 128 | 133 | memcpy(buf->p, data, datalen); | |
| 129 | memcpy(buf->p, data, datalen); | 134 | buf->p += datalen; |
| 130 | buf->p += datalen; | 135 | } |
| 131 | } | 136 | } |
| 132 | 137 | ||
| 133 | static inline u8 buf_get_int8(struct cbuf *buf) | 138 | static inline u8 buf_get_int8(struct cbuf *buf) |
| 134 | { | 139 | { |
| 135 | u8 ret = 0; | 140 | u8 ret = 0; |
| 136 | 141 | ||
| 137 | buf_check_size(buf, 1); | 142 | if (buf_check_size(buf, 1)) { |
| 138 | ret = buf->p[0]; | 143 | ret = buf->p[0]; |
| 139 | 144 | buf->p++; | |
| 140 | buf->p++; | 145 | } |
| 141 | 146 | ||
| 142 | return ret; | 147 | return ret; |
| 143 | } | 148 | } |
| @@ -146,10 +151,10 @@ static inline u16 buf_get_int16(struct cbuf *buf) | |||
| 146 | { | 151 | { |
| 147 | u16 ret = 0; | 152 | u16 ret = 0; |
| 148 | 153 | ||
| 149 | buf_check_size(buf, 2); | 154 | if (buf_check_size(buf, 2)) { |
| 150 | ret = le16_to_cpu(*(__le16 *)buf->p); | 155 | ret = le16_to_cpu(*(__le16 *)buf->p); |
| 151 | 156 | buf->p += 2; | |
| 152 | buf->p += 2; | 157 | } |
| 153 | 158 | ||
| 154 | return ret; | 159 | return ret; |
| 155 | } | 160 | } |
| @@ -158,10 +163,10 @@ static inline u32 buf_get_int32(struct cbuf *buf) | |||
| 158 | { | 163 | { |
| 159 | u32 ret = 0; | 164 | u32 ret = 0; |
| 160 | 165 | ||
| 161 | buf_check_size(buf, 4); | 166 | if (buf_check_size(buf, 4)) { |
| 162 | ret = le32_to_cpu(*(__le32 *)buf->p); | 167 | ret = le32_to_cpu(*(__le32 *)buf->p); |
| 163 | 168 | buf->p += 4; | |
| 164 | buf->p += 4; | 169 | } |
| 165 | 170 | ||
| 166 | return ret; | 171 | return ret; |
| 167 | } | 172 | } |
| @@ -170,10 +175,10 @@ static inline u64 buf_get_int64(struct cbuf *buf) | |||
| 170 | { | 175 | { |
| 171 | u64 ret = 0; | 176 | u64 ret = 0; |
| 172 | 177 | ||
| 173 | buf_check_size(buf, 8); | 178 | if (buf_check_size(buf, 8)) { |
| 174 | ret = le64_to_cpu(*(__le64 *)buf->p); | 179 | ret = le64_to_cpu(*(__le64 *)buf->p); |
| 175 | 180 | buf->p += 8; | |
| 176 | buf->p += 8; | 181 | } |
| 177 | 182 | ||
| 178 | return ret; | 183 | return ret; |
| 179 | } | 184 | } |
| @@ -181,27 +186,35 @@ static inline u64 buf_get_int64(struct cbuf *buf) | |||
| 181 | static inline int | 186 | static inline int |
| 182 | buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) | 187 | buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) |
| 183 | { | 188 | { |
| 189 | u16 len = 0; | ||
| 190 | |||
| 191 | len = buf_get_int16(buf); | ||
| 192 | if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) { | ||
| 193 | memcpy(data, buf->p, len); | ||
| 194 | data[len] = 0; | ||
| 195 | buf->p += len; | ||
| 196 | len++; | ||
| 197 | } | ||
| 184 | 198 | ||
| 185 | u16 len = buf_get_int16(buf); | 199 | return len; |
| 186 | buf_check_size(buf, len); | ||
| 187 | if (len + 1 > datalen) | ||
| 188 | return 0; | ||
| 189 | |||
| 190 | memcpy(data, buf->p, len); | ||
| 191 | data[len] = 0; | ||
| 192 | buf->p += len; | ||
| 193 | |||
| 194 | return len + 1; | ||
| 195 | } | 200 | } |
| 196 | 201 | ||
| 197 | static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) | 202 | static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) |
| 198 | { | 203 | { |
| 199 | char *ret = NULL; | 204 | char *ret; |
| 200 | int n = buf_get_string(buf, sbuf->p, sbuf->ep - sbuf->p); | 205 | u16 len; |
| 206 | |||
| 207 | ret = NULL; | ||
| 208 | len = buf_get_int16(buf); | ||
| 201 | 209 | ||
| 202 | if (n > 0) { | 210 | if (!buf_check_overflow(buf) && buf_check_size(buf, len) && |
| 211 | buf_check_size(sbuf, len+1)) { | ||
| 212 | |||
| 213 | memcpy(sbuf->p, buf->p, len); | ||
| 214 | sbuf->p[len] = 0; | ||
| 203 | ret = sbuf->p; | 215 | ret = sbuf->p; |
| 204 | sbuf->p += n; | 216 | buf->p += len; |
| 217 | sbuf->p += len + 1; | ||
| 205 | } | 218 | } |
| 206 | 219 | ||
| 207 | return ret; | 220 | return ret; |
| @@ -209,12 +222,15 @@ static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) | |||
| 209 | 222 | ||
| 210 | static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) | 223 | static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) |
| 211 | { | 224 | { |
| 212 | buf_check_size(buf, datalen); | 225 | int ret = 0; |
| 213 | 226 | ||
| 214 | memcpy(data, buf->p, datalen); | 227 | if (buf_check_size(buf, datalen)) { |
| 215 | buf->p += datalen; | 228 | memcpy(data, buf->p, datalen); |
| 229 | buf->p += datalen; | ||
| 230 | ret = datalen; | ||
| 231 | } | ||
| 216 | 232 | ||
| 217 | return datalen; | 233 | return ret; |
| 218 | } | 234 | } |
| 219 | 235 | ||
| 220 | static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, | 236 | 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, | |||
| 223 | char *ret = NULL; | 239 | char *ret = NULL; |
| 224 | int n = 0; | 240 | int n = 0; |
| 225 | 241 | ||
| 226 | buf_check_size(dbuf, datalen); | 242 | if (buf_check_size(dbuf, datalen)) { |
| 227 | 243 | n = buf_get_data(buf, dbuf->p, datalen); | |
| 228 | n = buf_get_data(buf, dbuf->p, datalen); | 244 | if (n > 0) { |
| 229 | 245 | ret = dbuf->p; | |
| 230 | if (n > 0) { | 246 | dbuf->p += n; |
| 231 | ret = dbuf->p; | 247 | } |
| 232 | dbuf->p += n; | ||
| 233 | } | 248 | } |
| 234 | 249 | ||
| 235 | return ret; | 250 | return ret; |
| @@ -636,7 +651,7 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, | |||
| 636 | break; | 651 | break; |
| 637 | case RWALK: | 652 | case RWALK: |
| 638 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); | 653 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); |
| 639 | rcall->params.rwalk.wqids = buf_alloc(bufp, | 654 | rcall->params.rwalk.wqids = buf_alloc(dbufp, |
| 640 | rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); | 655 | rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); |
| 641 | if (rcall->params.rwalk.wqids) | 656 | if (rcall->params.rwalk.wqids) |
| 642 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) { | 657 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) { |
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 821c9c4d76aa..d95f8626d170 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) | |||
| 71 | * | 71 | * |
| 72 | */ | 72 | */ |
| 73 | 73 | ||
| 74 | struct v9fs_fid *v9fs_fid_create(struct dentry *dentry) | 74 | struct v9fs_fid *v9fs_fid_create(struct dentry *dentry, |
| 75 | struct v9fs_session_info *v9ses, int fid, int create) | ||
| 75 | { | 76 | { |
| 76 | struct v9fs_fid *new; | 77 | struct v9fs_fid *new; |
| 77 | 78 | ||
| 79 | dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n", | ||
| 80 | dentry, fid, create); | ||
| 81 | |||
| 78 | new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); | 82 | new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); |
| 79 | if (new == NULL) { | 83 | if (new == NULL) { |
| 80 | dprintk(DEBUG_ERROR, "Out of Memory\n"); | 84 | dprintk(DEBUG_ERROR, "Out of Memory\n"); |
| 81 | return ERR_PTR(-ENOMEM); | 85 | return ERR_PTR(-ENOMEM); |
| 82 | } | 86 | } |
| 83 | 87 | ||
| 84 | new->fid = -1; | 88 | new->fid = fid; |
| 89 | new->v9ses = v9ses; | ||
| 85 | new->fidopen = 0; | 90 | new->fidopen = 0; |
| 86 | new->fidcreate = 0; | 91 | new->fidcreate = create; |
| 87 | new->fidclunked = 0; | 92 | new->fidclunked = 0; |
| 88 | new->iounit = 0; | 93 | new->iounit = 0; |
| 94 | new->rdir_pos = 0; | ||
| 95 | new->rdir_fcall = NULL; | ||
| 89 | 96 | ||
| 90 | if (v9fs_fid_insert(new, dentry) == 0) | 97 | if (v9fs_fid_insert(new, dentry) == 0) |
| 91 | return new; | 98 | return new; |
| @@ -109,6 +116,59 @@ void v9fs_fid_destroy(struct v9fs_fid *fid) | |||
| 109 | } | 116 | } |
| 110 | 117 | ||
| 111 | /** | 118 | /** |
| 119 | * v9fs_fid_walk_up - walks from the process current directory | ||
| 120 | * up to the specified dentry. | ||
| 121 | */ | ||
| 122 | static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) | ||
| 123 | { | ||
| 124 | int fidnum, cfidnum, err; | ||
| 125 | struct v9fs_fid *cfid; | ||
| 126 | struct dentry *cde; | ||
| 127 | struct v9fs_session_info *v9ses; | ||
| 128 | |||
| 129 | v9ses = v9fs_inode2v9ses(current->fs->pwd->d_inode); | ||
| 130 | cfid = v9fs_fid_lookup(current->fs->pwd); | ||
| 131 | if (cfid == NULL) { | ||
| 132 | dprintk(DEBUG_ERROR, "process cwd doesn't have a fid\n"); | ||
| 133 | return ERR_PTR(-ENOENT); | ||
| 134 | } | ||
| 135 | |||
| 136 | cfidnum = cfid->fid; | ||
| 137 | cde = current->fs->pwd; | ||
| 138 | /* TODO: take advantage of multiwalk */ | ||
| 139 | |||
| 140 | fidnum = v9fs_get_idpool(&v9ses->fidpool); | ||
| 141 | if (fidnum < 0) { | ||
| 142 | dprintk(DEBUG_ERROR, "could not get a new fid num\n"); | ||
| 143 | err = -ENOENT; | ||
| 144 | goto clunk_fid; | ||
| 145 | } | ||
| 146 | |||
| 147 | while (cde != dentry) { | ||
| 148 | if (cde == cde->d_parent) { | ||
| 149 | dprintk(DEBUG_ERROR, "can't find dentry\n"); | ||
| 150 | err = -ENOENT; | ||
| 151 | goto clunk_fid; | ||
| 152 | } | ||
| 153 | |||
| 154 | err = v9fs_t_walk(v9ses, cfidnum, fidnum, "..", NULL); | ||
| 155 | if (err < 0) { | ||
| 156 | dprintk(DEBUG_ERROR, "problem walking to parent\n"); | ||
| 157 | goto clunk_fid; | ||
| 158 | } | ||
| 159 | |||
| 160 | cfidnum = fidnum; | ||
| 161 | cde = cde->d_parent; | ||
| 162 | } | ||
| 163 | |||
| 164 | return v9fs_fid_create(dentry, v9ses, fidnum, 0); | ||
| 165 | |||
| 166 | clunk_fid: | ||
| 167 | v9fs_t_clunk(v9ses, fidnum, NULL); | ||
| 168 | return ERR_PTR(err); | ||
| 169 | } | ||
| 170 | |||
| 171 | /** | ||
| 112 | * v9fs_fid_lookup - retrieve the right fid from a particular dentry | 172 | * v9fs_fid_lookup - retrieve the right fid from a particular dentry |
| 113 | * @dentry: dentry to look for fid in | 173 | * @dentry: dentry to look for fid in |
| 114 | * @type: intent of lookup (operation or traversal) | 174 | * @type: intent of lookup (operation or traversal) |
| @@ -119,49 +179,25 @@ void v9fs_fid_destroy(struct v9fs_fid *fid) | |||
| 119 | * | 179 | * |
| 120 | */ | 180 | */ |
| 121 | 181 | ||
| 122 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type) | 182 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) |
| 123 | { | 183 | { |
| 124 | struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; | 184 | struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; |
| 125 | struct v9fs_fid *current_fid = NULL; | 185 | struct v9fs_fid *current_fid = NULL; |
| 126 | struct v9fs_fid *temp = NULL; | 186 | struct v9fs_fid *temp = NULL; |
| 127 | struct v9fs_fid *return_fid = NULL; | 187 | struct v9fs_fid *return_fid = NULL; |
| 128 | int found_parent = 0; | ||
| 129 | int found_user = 0; | ||
| 130 | 188 | ||
| 131 | dprintk(DEBUG_9P, " dentry: %s (%p) type %d\n", dentry->d_iname, dentry, | 189 | dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
| 132 | type); | ||
| 133 | 190 | ||
| 134 | if (fid_list && !list_empty(fid_list)) { | 191 | if (fid_list) { |
| 135 | list_for_each_entry_safe(current_fid, temp, fid_list, list) { | 192 | list_for_each_entry_safe(current_fid, temp, fid_list, list) { |
| 136 | if (current_fid->uid == current->uid) { | 193 | if (!current_fid->fidcreate) { |
| 137 | if (return_fid == NULL) { | 194 | return_fid = current_fid; |
| 138 | if ((type == FID_OP) | 195 | break; |
| 139 | || (!current_fid->fidopen)) { | ||
| 140 | return_fid = current_fid; | ||
| 141 | found_user = 1; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | } | ||
| 145 | if (current_fid->pid == current->real_parent->pid) { | ||
| 146 | if ((return_fid == NULL) || (found_parent) | ||
| 147 | || (found_user)) { | ||
| 148 | if ((type == FID_OP) | ||
| 149 | || (!current_fid->fidopen)) { | ||
| 150 | return_fid = current_fid; | ||
| 151 | found_parent = 1; | ||
| 152 | found_user = 0; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | if (current_fid->pid == current->pid) { | ||
| 157 | if ((type == FID_OP) || | ||
| 158 | (!current_fid->fidopen)) { | ||
| 159 | return_fid = current_fid; | ||
| 160 | found_parent = 0; | ||
| 161 | found_user = 0; | ||
| 162 | } | ||
| 163 | } | 196 | } |
| 164 | } | 197 | } |
| 198 | |||
| 199 | if (!return_fid) | ||
| 200 | return_fid = current_fid; | ||
| 165 | } | 201 | } |
| 166 | 202 | ||
| 167 | /* we are at the root but didn't match */ | 203 | /* we are at the root but didn't match */ |
| @@ -187,55 +223,33 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type) | |||
| 187 | 223 | ||
| 188 | /* XXX - there may be some duplication we can get rid of */ | 224 | /* XXX - there may be some duplication we can get rid of */ |
| 189 | if (par == dentry) { | 225 | if (par == dentry) { |
| 190 | /* we need to fid_lookup the starting point */ | 226 | return_fid = v9fs_fid_walk_up(dentry); |
| 191 | int fidnum = -1; | 227 | if (IS_ERR(return_fid)) |
| 192 | int oldfid = -1; | 228 | return_fid = NULL; |
| 193 | int result = -1; | 229 | } |
| 194 | struct v9fs_session_info *v9ses = | 230 | } |
| 195 | v9fs_inode2v9ses(current->fs->pwd->d_inode); | ||
| 196 | |||
| 197 | current_fid = | ||
| 198 | v9fs_fid_lookup(current->fs->pwd, FID_WALK); | ||
| 199 | if (current_fid == NULL) { | ||
| 200 | dprintk(DEBUG_ERROR, | ||
| 201 | "process cwd doesn't have a fid\n"); | ||
| 202 | return return_fid; | ||
| 203 | } | ||
| 204 | oldfid = current_fid->fid; | ||
| 205 | par = current->fs->pwd; | ||
| 206 | /* TODO: take advantage of multiwalk */ | ||
| 207 | 231 | ||
| 208 | fidnum = v9fs_get_idpool(&v9ses->fidpool); | 232 | return return_fid; |
| 209 | if (fidnum < 0) { | 233 | } |
| 210 | dprintk(DEBUG_ERROR, | ||
| 211 | "could not get a new fid num\n"); | ||
| 212 | return return_fid; | ||
| 213 | } | ||
| 214 | 234 | ||
| 215 | while (par != dentry) { | 235 | struct v9fs_fid *v9fs_fid_get_created(struct dentry *dentry) |
| 216 | result = | 236 | { |
| 217 | v9fs_t_walk(v9ses, oldfid, fidnum, "..", | 237 | struct list_head *fid_list; |
| 218 | NULL); | 238 | struct v9fs_fid *fid, *ftmp, *ret; |
| 219 | if (result < 0) { | 239 | |
| 220 | dprintk(DEBUG_ERROR, | 240 | dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
| 221 | "problem walking to parent\n"); | 241 | fid_list = (struct list_head *)dentry->d_fsdata; |
| 222 | 242 | ret = NULL; | |
| 223 | break; | 243 | if (fid_list) { |
| 224 | } | 244 | list_for_each_entry_safe(fid, ftmp, fid_list, list) { |
| 225 | oldfid = fidnum; | 245 | if (fid->fidcreate && fid->pid == current->pid) { |
| 226 | if (par == par->d_parent) { | 246 | list_del(&fid->list); |
| 227 | dprintk(DEBUG_ERROR, | 247 | ret = fid; |
| 228 | "can't find dentry\n"); | 248 | break; |
| 229 | break; | ||
| 230 | } | ||
| 231 | par = par->d_parent; | ||
| 232 | } | ||
| 233 | if (par == dentry) { | ||
| 234 | return_fid = v9fs_fid_create(dentry); | ||
| 235 | return_fid->fid = fidnum; | ||
| 236 | } | 249 | } |
| 237 | } | 250 | } |
| 238 | } | 251 | } |
| 239 | 252 | ||
| 240 | return return_fid; | 253 | dprintk(DEBUG_9P, "return %p\n", ret); |
| 254 | return ret; | ||
| 241 | } | 255 | } |
diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 7db478ccca36..84c673a44c83 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | #define FID_OP 0 | 26 | #define FID_OP 0 |
| 27 | #define FID_WALK 1 | 27 | #define FID_WALK 1 |
| 28 | #define FID_CREATE 2 | ||
| 28 | 29 | ||
| 29 | struct v9fs_fid { | 30 | struct v9fs_fid { |
| 30 | struct list_head list; /* list of fids associated with a dentry */ | 31 | struct list_head list; /* list of fids associated with a dentry */ |
| @@ -52,6 +53,8 @@ struct v9fs_fid { | |||
| 52 | struct v9fs_session_info *v9ses; /* session info for this FID */ | 53 | struct v9fs_session_info *v9ses; /* session info for this FID */ |
| 53 | }; | 54 | }; |
| 54 | 55 | ||
| 55 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type); | 56 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); |
| 57 | struct v9fs_fid *v9fs_fid_get_created(struct dentry *); | ||
| 56 | void v9fs_fid_destroy(struct v9fs_fid *fid); | 58 | void v9fs_fid_destroy(struct v9fs_fid *fid); |
| 57 | struct v9fs_fid *v9fs_fid_create(struct dentry *); | 59 | struct v9fs_fid *v9fs_fid_create(struct dentry *, |
| 60 | struct v9fs_session_info *v9ses, int fid, int create); | ||
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 13bdbbab4387..82303f3bf76f 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
| @@ -303,7 +303,13 @@ v9fs_session_init(struct v9fs_session_info *v9ses, | |||
| 303 | goto SessCleanUp; | 303 | goto SessCleanUp; |
| 304 | }; | 304 | }; |
| 305 | 305 | ||
| 306 | v9ses->transport = trans_proto; | 306 | v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL); |
| 307 | if (!v9ses->transport) { | ||
| 308 | retval = -ENOMEM; | ||
| 309 | goto SessCleanUp; | ||
| 310 | } | ||
| 311 | |||
| 312 | memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport)); | ||
| 307 | 313 | ||
| 308 | if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) { | 314 | if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) { |
| 309 | eprintk(KERN_ERR, "problem initializing transport\n"); | 315 | eprintk(KERN_ERR, "problem initializing transport\n"); |
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 306c96741f81..a6aa947de0f9 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) | |||
| 67 | struct dentry *dc = current->fs->pwd; | 67 | struct dentry *dc = current->fs->pwd; |
| 68 | 68 | ||
| 69 | dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); | 69 | dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); |
| 70 | if (v9fs_fid_lookup(dentry, FID_OP)) { | 70 | if (v9fs_fid_lookup(dentry)) { |
| 71 | dprintk(DEBUG_VFS, "VALID\n"); | 71 | dprintk(DEBUG_VFS, "VALID\n"); |
| 72 | return 1; | 72 | return 1; |
| 73 | } | 73 | } |
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index c478a7384186..57a43b8feef5 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) | |||
| 197 | filemap_fdatawait(inode->i_mapping); | 197 | filemap_fdatawait(inode->i_mapping); |
| 198 | 198 | ||
| 199 | if (fidnum >= 0) { | 199 | if (fidnum >= 0) { |
| 200 | fid->fidopen--; | ||
| 201 | dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, | 200 | dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, |
| 202 | fid->fid); | 201 | fid->fid); |
| 203 | 202 | ||
| 204 | if (fid->fidopen == 0) { | 203 | if (v9fs_t_clunk(v9ses, fidnum, NULL)) |
| 205 | if (v9fs_t_clunk(v9ses, fidnum, NULL)) | 204 | dprintk(DEBUG_ERROR, "clunk failed\n"); |
| 206 | dprintk(DEBUG_ERROR, "clunk failed\n"); | ||
| 207 | 205 | ||
| 208 | v9fs_put_idpool(fid->fid, &v9ses->fidpool); | 206 | v9fs_put_idpool(fid->fid, &v9ses->fidpool); |
| 209 | } | ||
| 210 | 207 | ||
| 211 | kfree(fid->rdir_fcall); | 208 | kfree(fid->rdir_fcall); |
| 209 | kfree(fid); | ||
| 212 | 210 | ||
| 213 | filp->private_data = NULL; | 211 | filp->private_data = NULL; |
| 214 | v9fs_fid_destroy(fid); | ||
| 215 | } | 212 | } |
| 216 | 213 | ||
| 217 | d_drop(filp->f_dentry); | 214 | d_drop(filp->f_dentry); |
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 1f8ae7d580ab..a4799e971d1c 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
| @@ -53,30 +53,36 @@ | |||
| 53 | int v9fs_file_open(struct inode *inode, struct file *file) | 53 | int v9fs_file_open(struct inode *inode, struct file *file) |
| 54 | { | 54 | { |
| 55 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 55 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
| 56 | struct v9fs_fid *v9fid = v9fs_fid_lookup(file->f_dentry, FID_WALK); | 56 | struct v9fs_fid *v9fid, *fid; |
| 57 | struct v9fs_fid *v9newfid = NULL; | ||
| 58 | struct v9fs_fcall *fcall = NULL; | 57 | struct v9fs_fcall *fcall = NULL; |
| 59 | int open_mode = 0; | 58 | int open_mode = 0; |
| 60 | unsigned int iounit = 0; | 59 | unsigned int iounit = 0; |
| 61 | int newfid = -1; | 60 | int newfid = -1; |
| 62 | long result = -1; | 61 | long result = -1; |
| 63 | 62 | ||
| 64 | dprintk(DEBUG_VFS, "inode: %p file: %p v9fid= %p\n", inode, file, | 63 | dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); |
| 65 | v9fid); | 64 | |
| 65 | v9fid = v9fs_fid_get_created(file->f_dentry); | ||
| 66 | if (!v9fid) | ||
| 67 | v9fid = v9fs_fid_lookup(file->f_dentry); | ||
| 66 | 68 | ||
| 67 | if (!v9fid) { | 69 | if (!v9fid) { |
| 68 | struct dentry *dentry = file->f_dentry; | ||
| 69 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); | 70 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); |
| 71 | return -EBADF; | ||
| 72 | } | ||
| 70 | 73 | ||
| 71 | /* XXX - some duplication from lookup, generalize later */ | 74 | if (!v9fid->fidcreate) { |
| 72 | /* basically vfs_lookup is too heavy weight */ | 75 | fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); |
| 73 | v9fid = v9fs_fid_lookup(file->f_dentry, FID_OP); | 76 | if (fid == NULL) { |
| 74 | if (!v9fid) | 77 | dprintk(DEBUG_ERROR, "Out of Memory\n"); |
| 75 | return -EBADF; | 78 | return -ENOMEM; |
| 79 | } | ||
| 76 | 80 | ||
| 77 | v9fid = v9fs_fid_lookup(dentry->d_parent, FID_WALK); | 81 | fid->fidopen = 0; |
| 78 | if (!v9fid) | 82 | fid->fidcreate = 0; |
| 79 | return -EBADF; | 83 | fid->fidclunked = 0; |
| 84 | fid->iounit = 0; | ||
| 85 | fid->v9ses = v9ses; | ||
| 80 | 86 | ||
| 81 | newfid = v9fs_get_idpool(&v9ses->fidpool); | 87 | newfid = v9fs_get_idpool(&v9ses->fidpool); |
| 82 | if (newfid < 0) { | 88 | if (newfid < 0) { |
| @@ -85,58 +91,16 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
| 85 | } | 91 | } |
| 86 | 92 | ||
| 87 | result = | 93 | result = |
| 88 | v9fs_t_walk(v9ses, v9fid->fid, newfid, | 94 | v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); |
| 89 | (char *)file->f_dentry->d_name.name, NULL); | 95 | |
| 90 | if (result < 0) { | 96 | if (result < 0) { |
| 91 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 97 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
| 92 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); | 98 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); |
| 93 | return -EBADF; | 99 | return -EBADF; |
| 94 | } | 100 | } |
| 95 | 101 | ||
| 96 | v9fid = v9fs_fid_create(dentry); | 102 | fid->fid = newfid; |
| 97 | if (v9fid == NULL) { | 103 | v9fid = fid; |
| 98 | dprintk(DEBUG_ERROR, "couldn't insert\n"); | ||
| 99 | return -ENOMEM; | ||
| 100 | } | ||
| 101 | v9fid->fid = newfid; | ||
| 102 | } | ||
| 103 | |||
| 104 | if (v9fid->fidcreate) { | ||
| 105 | /* create case */ | ||
| 106 | newfid = v9fid->fid; | ||
| 107 | iounit = v9fid->iounit; | ||
| 108 | v9fid->fidcreate = 0; | ||
| 109 | } else { | ||
| 110 | if (!S_ISDIR(inode->i_mode)) | ||
| 111 | newfid = v9fid->fid; | ||
| 112 | else { | ||
| 113 | newfid = v9fs_get_idpool(&v9ses->fidpool); | ||
| 114 | if (newfid < 0) { | ||
| 115 | eprintk(KERN_WARNING, "allocation failed\n"); | ||
| 116 | return -ENOSPC; | ||
| 117 | } | ||
| 118 | /* This would be a somewhat critical clone */ | ||
| 119 | result = | ||
| 120 | v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, | ||
| 121 | &fcall); | ||
| 122 | if (result < 0) { | ||
| 123 | dprintk(DEBUG_ERROR, "clone error: %s\n", | ||
| 124 | FCALL_ERROR(fcall)); | ||
| 125 | kfree(fcall); | ||
| 126 | return result; | ||
| 127 | } | ||
| 128 | |||
| 129 | v9newfid = v9fs_fid_create(file->f_dentry); | ||
| 130 | v9newfid->fid = newfid; | ||
| 131 | v9newfid->qid = v9fid->qid; | ||
| 132 | v9newfid->iounit = v9fid->iounit; | ||
| 133 | v9newfid->fidopen = 0; | ||
| 134 | v9newfid->fidclunked = 0; | ||
| 135 | v9newfid->v9ses = v9ses; | ||
| 136 | v9fid = v9newfid; | ||
| 137 | kfree(fcall); | ||
| 138 | } | ||
| 139 | |||
| 140 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ | 104 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ |
| 141 | /* translate open mode appropriately */ | 105 | /* translate open mode appropriately */ |
| 142 | open_mode = file->f_flags & 0x3; | 106 | open_mode = file->f_flags & 0x3; |
| @@ -163,9 +127,13 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
| 163 | 127 | ||
| 164 | iounit = fcall->params.ropen.iounit; | 128 | iounit = fcall->params.ropen.iounit; |
| 165 | kfree(fcall); | 129 | kfree(fcall); |
| 130 | } else { | ||
| 131 | /* create case */ | ||
| 132 | newfid = v9fid->fid; | ||
| 133 | iounit = v9fid->iounit; | ||
| 134 | v9fid->fidcreate = 0; | ||
| 166 | } | 135 | } |
| 167 | 136 | ||
| 168 | |||
| 169 | file->private_data = v9fid; | 137 | file->private_data = v9fid; |
| 170 | 138 | ||
| 171 | v9fid->rdir_pos = 0; | 139 | v9fid->rdir_pos = 0; |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 0c13fc600049..2b696ae6655a 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
| @@ -307,7 +307,7 @@ v9fs_create(struct inode *dir, | |||
| 307 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | 307 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); |
| 308 | struct super_block *sb = dir->i_sb; | 308 | struct super_block *sb = dir->i_sb; |
| 309 | struct v9fs_fid *dirfid = | 309 | struct v9fs_fid *dirfid = |
| 310 | v9fs_fid_lookup(file_dentry->d_parent, FID_WALK); | 310 | v9fs_fid_lookup(file_dentry->d_parent); |
| 311 | struct v9fs_fid *fid = NULL; | 311 | struct v9fs_fid *fid = NULL; |
| 312 | struct inode *file_inode = NULL; | 312 | struct inode *file_inode = NULL; |
| 313 | struct v9fs_fcall *fcall = NULL; | 313 | struct v9fs_fcall *fcall = NULL; |
| @@ -317,6 +317,7 @@ v9fs_create(struct inode *dir, | |||
| 317 | long newfid = -1; | 317 | long newfid = -1; |
| 318 | int result = 0; | 318 | int result = 0; |
| 319 | unsigned int iounit = 0; | 319 | unsigned int iounit = 0; |
| 320 | int wfidno = -1; | ||
| 320 | 321 | ||
| 321 | perm = unixmode2p9mode(v9ses, perm); | 322 | perm = unixmode2p9mode(v9ses, perm); |
| 322 | 323 | ||
| @@ -350,7 +351,7 @@ v9fs_create(struct inode *dir, | |||
| 350 | if (result < 0) { | 351 | if (result < 0) { |
| 351 | dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); | 352 | dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); |
| 352 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 353 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
| 353 | newfid = 0; | 354 | newfid = -1; |
| 354 | goto CleanUpFid; | 355 | goto CleanUpFid; |
| 355 | } | 356 | } |
| 356 | 357 | ||
| @@ -369,20 +370,39 @@ v9fs_create(struct inode *dir, | |||
| 369 | qid = fcall->params.rcreate.qid; | 370 | qid = fcall->params.rcreate.qid; |
| 370 | kfree(fcall); | 371 | kfree(fcall); |
| 371 | 372 | ||
| 372 | fid = v9fs_fid_create(file_dentry); | 373 | fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); |
| 374 | dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); | ||
| 373 | if (!fid) { | 375 | if (!fid) { |
| 374 | result = -ENOMEM; | 376 | result = -ENOMEM; |
| 375 | goto CleanUpFid; | 377 | goto CleanUpFid; |
| 376 | } | 378 | } |
| 377 | 379 | ||
| 378 | fid->fid = newfid; | ||
| 379 | fid->fidopen = 0; | ||
| 380 | fid->fidcreate = 1; | ||
| 381 | fid->qid = qid; | 380 | fid->qid = qid; |
| 382 | fid->iounit = iounit; | 381 | fid->iounit = iounit; |
| 383 | fid->rdir_pos = 0; | 382 | |
| 384 | fid->rdir_fcall = NULL; | 383 | /* walk to the newly created file and put the fid in the dentry */ |
| 385 | fid->v9ses = v9ses; | 384 | wfidno = v9fs_get_idpool(&v9ses->fidpool); |
| 385 | if (newfid < 0) { | ||
| 386 | eprintk(KERN_WARNING, "no free fids available\n"); | ||
| 387 | return -ENOSPC; | ||
| 388 | } | ||
| 389 | |||
| 390 | result = v9fs_t_walk(v9ses, dirfidnum, wfidno, | ||
| 391 | (char *) file_dentry->d_name.name, NULL); | ||
| 392 | if (result < 0) { | ||
| 393 | dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); | ||
| 394 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | ||
| 395 | wfidno = -1; | ||
| 396 | goto CleanUpFid; | ||
| 397 | } | ||
| 398 | |||
| 399 | if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { | ||
| 400 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) { | ||
| 401 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | ||
| 402 | } | ||
| 403 | |||
| 404 | goto CleanUpFid; | ||
| 405 | } | ||
| 386 | 406 | ||
| 387 | if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) || | 407 | if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) || |
| 388 | (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) || | 408 | (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) || |
| @@ -410,11 +430,11 @@ v9fs_create(struct inode *dir, | |||
| 410 | d_instantiate(file_dentry, file_inode); | 430 | d_instantiate(file_dentry, file_inode); |
| 411 | 431 | ||
| 412 | if (perm & V9FS_DMDIR) { | 432 | if (perm & V9FS_DMDIR) { |
| 413 | if (v9fs_t_clunk(v9ses, newfid, &fcall)) | 433 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) |
| 434 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
| 435 | else | ||
| 414 | dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n", | 436 | dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n", |
| 415 | FCALL_ERROR(fcall)); | 437 | FCALL_ERROR(fcall)); |
| 416 | |||
| 417 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
| 418 | kfree(fcall); | 438 | kfree(fcall); |
| 419 | fid->fidopen = 0; | 439 | fid->fidopen = 0; |
| 420 | fid->fidcreate = 0; | 440 | fid->fidcreate = 0; |
| @@ -426,12 +446,22 @@ v9fs_create(struct inode *dir, | |||
| 426 | CleanUpFid: | 446 | CleanUpFid: |
| 427 | kfree(fcall); | 447 | kfree(fcall); |
| 428 | 448 | ||
| 429 | if (newfid) { | 449 | if (newfid >= 0) { |
| 430 | if (v9fs_t_clunk(v9ses, newfid, &fcall)) | 450 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) |
| 451 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
| 452 | else | ||
| 453 | dprintk(DEBUG_ERROR, "clunk failed: %s\n", | ||
| 454 | FCALL_ERROR(fcall)); | ||
| 455 | |||
| 456 | kfree(fcall); | ||
| 457 | } | ||
| 458 | if (wfidno >= 0) { | ||
| 459 | if (!v9fs_t_clunk(v9ses, wfidno, &fcall)) | ||
| 460 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | ||
| 461 | else | ||
| 431 | dprintk(DEBUG_ERROR, "clunk failed: %s\n", | 462 | dprintk(DEBUG_ERROR, "clunk failed: %s\n", |
| 432 | FCALL_ERROR(fcall)); | 463 | FCALL_ERROR(fcall)); |
| 433 | 464 | ||
| 434 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
| 435 | kfree(fcall); | 465 | kfree(fcall); |
| 436 | } | 466 | } |
| 437 | return result; | 467 | return result; |
| @@ -461,7 +491,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | |||
| 461 | file_inode = file->d_inode; | 491 | file_inode = file->d_inode; |
| 462 | sb = file_inode->i_sb; | 492 | sb = file_inode->i_sb; |
| 463 | v9ses = v9fs_inode2v9ses(file_inode); | 493 | v9ses = v9fs_inode2v9ses(file_inode); |
| 464 | v9fid = v9fs_fid_lookup(file, FID_OP); | 494 | v9fid = v9fs_fid_lookup(file); |
| 465 | 495 | ||
| 466 | if (!v9fid) { | 496 | if (!v9fid) { |
| 467 | dprintk(DEBUG_ERROR, | 497 | dprintk(DEBUG_ERROR, |
| @@ -545,7 +575,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 545 | 575 | ||
| 546 | sb = dir->i_sb; | 576 | sb = dir->i_sb; |
| 547 | v9ses = v9fs_inode2v9ses(dir); | 577 | v9ses = v9fs_inode2v9ses(dir); |
| 548 | dirfid = v9fs_fid_lookup(dentry->d_parent, FID_WALK); | 578 | dirfid = v9fs_fid_lookup(dentry->d_parent); |
| 549 | 579 | ||
| 550 | if (!dirfid) { | 580 | if (!dirfid) { |
| 551 | dprintk(DEBUG_ERROR, "no dirfid\n"); | 581 | dprintk(DEBUG_ERROR, "no dirfid\n"); |
| @@ -573,7 +603,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 573 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 603 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
| 574 | if (result == -ENOENT) { | 604 | if (result == -ENOENT) { |
| 575 | d_add(dentry, NULL); | 605 | d_add(dentry, NULL); |
| 576 | dprintk(DEBUG_ERROR, | 606 | dprintk(DEBUG_VFS, |
| 577 | "Return negative dentry %p count %d\n", | 607 | "Return negative dentry %p count %d\n", |
| 578 | dentry, atomic_read(&dentry->d_count)); | 608 | dentry, atomic_read(&dentry->d_count)); |
| 579 | return NULL; | 609 | return NULL; |
| @@ -601,16 +631,13 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 601 | 631 | ||
| 602 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); | 632 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); |
| 603 | 633 | ||
| 604 | fid = v9fs_fid_create(dentry); | 634 | fid = v9fs_fid_create(dentry, v9ses, newfid, 0); |
| 605 | if (fid == NULL) { | 635 | if (fid == NULL) { |
| 606 | dprintk(DEBUG_ERROR, "couldn't insert\n"); | 636 | dprintk(DEBUG_ERROR, "couldn't insert\n"); |
| 607 | result = -ENOMEM; | 637 | result = -ENOMEM; |
| 608 | goto FreeFcall; | 638 | goto FreeFcall; |
| 609 | } | 639 | } |
| 610 | 640 | ||
| 611 | fid->fid = newfid; | ||
| 612 | fid->fidopen = 0; | ||
| 613 | fid->v9ses = v9ses; | ||
| 614 | fid->qid = fcall->params.rstat.stat->qid; | 641 | fid->qid = fcall->params.rstat.stat->qid; |
| 615 | 642 | ||
| 616 | dentry->d_op = &v9fs_dentry_operations; | 643 | dentry->d_op = &v9fs_dentry_operations; |
| @@ -665,11 +692,11 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 665 | { | 692 | { |
| 666 | struct inode *old_inode = old_dentry->d_inode; | 693 | struct inode *old_inode = old_dentry->d_inode; |
| 667 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); | 694 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); |
| 668 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_WALK); | 695 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); |
| 669 | struct v9fs_fid *olddirfid = | 696 | struct v9fs_fid *olddirfid = |
| 670 | v9fs_fid_lookup(old_dentry->d_parent, FID_WALK); | 697 | v9fs_fid_lookup(old_dentry->d_parent); |
| 671 | struct v9fs_fid *newdirfid = | 698 | struct v9fs_fid *newdirfid = |
| 672 | v9fs_fid_lookup(new_dentry->d_parent, FID_WALK); | 699 | v9fs_fid_lookup(new_dentry->d_parent); |
| 673 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | 700 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); |
| 674 | struct v9fs_fcall *fcall = NULL; | 701 | struct v9fs_fcall *fcall = NULL; |
| 675 | int fid = -1; | 702 | int fid = -1; |
| @@ -744,7 +771,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 744 | { | 771 | { |
| 745 | struct v9fs_fcall *fcall = NULL; | 772 | struct v9fs_fcall *fcall = NULL; |
| 746 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 773 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
| 747 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); | 774 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
| 748 | int err = -EPERM; | 775 | int err = -EPERM; |
| 749 | 776 | ||
| 750 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); | 777 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); |
| @@ -778,7 +805,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 778 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | 805 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) |
| 779 | { | 806 | { |
| 780 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 807 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
| 781 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); | 808 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
| 782 | struct v9fs_fcall *fcall = NULL; | 809 | struct v9fs_fcall *fcall = NULL; |
| 783 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | 810 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); |
| 784 | int res = -EPERM; | 811 | int res = -EPERM; |
| @@ -960,7 +987,7 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | |||
| 960 | if (retval != 0) | 987 | if (retval != 0) |
| 961 | goto FreeFcall; | 988 | goto FreeFcall; |
| 962 | 989 | ||
| 963 | newfid = v9fs_fid_lookup(dentry, FID_OP); | 990 | newfid = v9fs_fid_lookup(dentry); |
| 964 | 991 | ||
| 965 | /* issue a twstat */ | 992 | /* issue a twstat */ |
| 966 | v9fs_blank_mistat(v9ses, mistat); | 993 | v9fs_blank_mistat(v9ses, mistat); |
| @@ -1004,7 +1031,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
| 1004 | 1031 | ||
| 1005 | struct v9fs_fcall *fcall = NULL; | 1032 | struct v9fs_fcall *fcall = NULL; |
| 1006 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 1033 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
| 1007 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); | 1034 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
| 1008 | 1035 | ||
| 1009 | if (!fid) { | 1036 | if (!fid) { |
| 1010 | dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n"); | 1037 | 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, | |||
| 1063 | int ret; | 1090 | int ret; |
| 1064 | char *link = __getname(); | 1091 | char *link = __getname(); |
| 1065 | 1092 | ||
| 1066 | if (strlen(link) < buflen) | 1093 | if (buflen > PATH_MAX) |
| 1067 | buflen = strlen(link); | 1094 | buflen = PATH_MAX; |
| 1068 | 1095 | ||
| 1069 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); | 1096 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
| 1070 | 1097 | ||
| @@ -1148,7 +1175,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
| 1148 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | 1175 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); |
| 1149 | struct v9fs_fcall *fcall = NULL; | 1176 | struct v9fs_fcall *fcall = NULL; |
| 1150 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | 1177 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); |
| 1151 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_OP); | 1178 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); |
| 1152 | struct v9fs_fid *newfid = NULL; | 1179 | struct v9fs_fid *newfid = NULL; |
| 1153 | char *symname = __getname(); | 1180 | char *symname = __getname(); |
| 1154 | 1181 | ||
| @@ -1168,7 +1195,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
| 1168 | if (retval != 0) | 1195 | if (retval != 0) |
| 1169 | goto FreeMem; | 1196 | goto FreeMem; |
| 1170 | 1197 | ||
| 1171 | newfid = v9fs_fid_lookup(dentry, FID_OP); | 1198 | newfid = v9fs_fid_lookup(dentry); |
| 1172 | if (!newfid) { | 1199 | if (!newfid) { |
| 1173 | dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); | 1200 | dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); |
| 1174 | goto FreeMem; | 1201 | goto FreeMem; |
| @@ -1246,7 +1273,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
| 1246 | if (retval != 0) | 1273 | if (retval != 0) |
| 1247 | goto FreeMem; | 1274 | goto FreeMem; |
| 1248 | 1275 | ||
| 1249 | newfid = v9fs_fid_lookup(dentry, FID_OP); | 1276 | newfid = v9fs_fid_lookup(dentry); |
| 1250 | if (!newfid) { | 1277 | if (!newfid) { |
| 1251 | dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n"); | 1278 | dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n"); |
| 1252 | retval = -EINVAL; | 1279 | retval = -EINVAL; |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 868f350b2c5f..82c5b0084079 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 | |||
| 129 | 129 | ||
| 130 | if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { | 130 | if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { |
| 131 | dprintk(DEBUG_ERROR, "problem initiating session\n"); | 131 | dprintk(DEBUG_ERROR, "problem initiating session\n"); |
| 132 | retval = newfid; | 132 | return ERR_PTR(newfid); |
| 133 | goto free_session; | ||
| 134 | } | 133 | } |
| 135 | 134 | ||
| 136 | sb = sget(fs_type, NULL, v9fs_set_super, v9ses); | 135 | sb = sget(fs_type, NULL, v9fs_set_super, v9ses); |
| @@ -150,28 +149,24 @@ static struct super_block *v9fs_get_sb(struct file_system_type | |||
| 150 | 149 | ||
| 151 | if (!root) { | 150 | if (!root) { |
| 152 | retval = -ENOMEM; | 151 | retval = -ENOMEM; |
| 153 | goto release_inode; | 152 | goto put_back_sb; |
| 154 | } | 153 | } |
| 155 | 154 | ||
| 156 | sb->s_root = root; | 155 | sb->s_root = root; |
| 157 | 156 | ||
| 158 | /* Setup the Root Inode */ | ||
| 159 | root_fid = v9fs_fid_create(root); | ||
| 160 | if (root_fid == NULL) { | ||
| 161 | retval = -ENOMEM; | ||
| 162 | goto release_dentry; | ||
| 163 | } | ||
| 164 | |||
| 165 | root_fid->fidopen = 0; | ||
| 166 | root_fid->v9ses = v9ses; | ||
| 167 | |||
| 168 | stat_result = v9fs_t_stat(v9ses, newfid, &fcall); | 157 | stat_result = v9fs_t_stat(v9ses, newfid, &fcall); |
| 169 | if (stat_result < 0) { | 158 | if (stat_result < 0) { |
| 170 | dprintk(DEBUG_ERROR, "stat error\n"); | 159 | dprintk(DEBUG_ERROR, "stat error\n"); |
| 171 | v9fs_t_clunk(v9ses, newfid, NULL); | 160 | v9fs_t_clunk(v9ses, newfid, NULL); |
| 172 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 161 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
| 173 | } else { | 162 | } else { |
| 174 | root_fid->fid = newfid; | 163 | /* Setup the Root Inode */ |
| 164 | root_fid = v9fs_fid_create(root, v9ses, newfid, 0); | ||
| 165 | if (root_fid == NULL) { | ||
| 166 | retval = -ENOMEM; | ||
| 167 | goto put_back_sb; | ||
| 168 | } | ||
| 169 | |||
| 175 | root_fid->qid = fcall->params.rstat.stat->qid; | 170 | root_fid->qid = fcall->params.rstat.stat->qid; |
| 176 | root->d_inode->i_ino = | 171 | root->d_inode->i_ino = |
| 177 | v9fs_qid2ino(&fcall->params.rstat.stat->qid); | 172 | v9fs_qid2ino(&fcall->params.rstat.stat->qid); |
| @@ -182,25 +177,15 @@ static struct super_block *v9fs_get_sb(struct file_system_type | |||
| 182 | 177 | ||
| 183 | if (stat_result < 0) { | 178 | if (stat_result < 0) { |
| 184 | retval = stat_result; | 179 | retval = stat_result; |
| 185 | goto release_dentry; | 180 | goto put_back_sb; |
| 186 | } | 181 | } |
| 187 | 182 | ||
| 188 | return sb; | 183 | return sb; |
| 189 | 184 | ||
| 190 | release_dentry: | 185 | put_back_sb: |
| 191 | dput(sb->s_root); | 186 | /* deactivate_super calls v9fs_kill_super which will frees the rest */ |
| 192 | |||
| 193 | release_inode: | ||
| 194 | iput(inode); | ||
| 195 | |||
| 196 | put_back_sb: | ||
| 197 | up_write(&sb->s_umount); | 187 | up_write(&sb->s_umount); |
| 198 | deactivate_super(sb); | 188 | deactivate_super(sb); |
| 199 | v9fs_session_close(v9ses); | ||
| 200 | |||
| 201 | free_session: | ||
| 202 | kfree(v9ses); | ||
| 203 | |||
| 204 | return ERR_PTR(retval); | 189 | return ERR_PTR(retval); |
| 205 | } | 190 | } |
| 206 | 191 | ||
diff --git a/fs/Kconfig b/fs/Kconfig index 068ccea2f184..48f5422cb19a 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
| @@ -472,6 +472,9 @@ config FUSE_FS | |||
| 472 | utilities is available from the FUSE homepage: | 472 | utilities is available from the FUSE homepage: |
| 473 | <http://fuse.sourceforge.net/> | 473 | <http://fuse.sourceforge.net/> |
| 474 | 474 | ||
| 475 | See <file:Documentation/filesystems/fuse.txt> for more information. | ||
| 476 | See <file:Documentation/Changes> for needed library/utility version. | ||
| 477 | |||
| 475 | If you want to develop a userspace FS, or if you want to use | 478 | If you want to develop a userspace FS, or if you want to use |
| 476 | a filesystem based on FUSE, answer Y or M. | 479 | a filesystem based on FUSE, answer Y or M. |
| 477 | 480 | ||
| @@ -562,6 +562,7 @@ static inline void lock_kiocb(struct kiocb *iocb) | |||
| 562 | static inline void unlock_kiocb(struct kiocb *iocb) | 562 | static inline void unlock_kiocb(struct kiocb *iocb) |
| 563 | { | 563 | { |
| 564 | kiocbClearLocked(iocb); | 564 | kiocbClearLocked(iocb); |
| 565 | smp_mb__after_clear_bit(); | ||
| 565 | wake_up_bit(&iocb->ki_flags, KIF_LOCKED); | 566 | wake_up_bit(&iocb->ki_flags, KIF_LOCKED); |
| 566 | } | 567 | } |
| 567 | 568 | ||
| @@ -740,19 +741,9 @@ static ssize_t aio_run_iocb(struct kiocb *iocb) | |||
| 740 | ret = retry(iocb); | 741 | ret = retry(iocb); |
| 741 | current->io_wait = NULL; | 742 | current->io_wait = NULL; |
| 742 | 743 | ||
| 743 | if (-EIOCBRETRY != ret) { | 744 | if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) { |
| 744 | if (-EIOCBQUEUED != ret) { | 745 | BUG_ON(!list_empty(&iocb->ki_wait.task_list)); |
| 745 | BUG_ON(!list_empty(&iocb->ki_wait.task_list)); | 746 | aio_complete(iocb, ret, 0); |
| 746 | aio_complete(iocb, ret, 0); | ||
| 747 | /* must not access the iocb after this */ | ||
| 748 | } | ||
| 749 | } else { | ||
| 750 | /* | ||
| 751 | * Issue an additional retry to avoid waiting forever if | ||
| 752 | * no waits were queued (e.g. in case of a short read). | ||
| 753 | */ | ||
| 754 | if (list_empty(&iocb->ki_wait.task_list)) | ||
| 755 | kiocbSetKicked(iocb); | ||
| 756 | } | 747 | } |
| 757 | out: | 748 | out: |
| 758 | spin_lock_irq(&ctx->ctx_lock); | 749 | spin_lock_irq(&ctx->ctx_lock); |
| @@ -898,16 +889,24 @@ static void aio_kick_handler(void *data) | |||
| 898 | * and if required activate the aio work queue to process | 889 | * and if required activate the aio work queue to process |
| 899 | * it | 890 | * it |
| 900 | */ | 891 | */ |
| 901 | static void queue_kicked_iocb(struct kiocb *iocb) | 892 | static void try_queue_kicked_iocb(struct kiocb *iocb) |
| 902 | { | 893 | { |
| 903 | struct kioctx *ctx = iocb->ki_ctx; | 894 | struct kioctx *ctx = iocb->ki_ctx; |
| 904 | unsigned long flags; | 895 | unsigned long flags; |
| 905 | int run = 0; | 896 | int run = 0; |
| 906 | 897 | ||
| 907 | WARN_ON((!list_empty(&iocb->ki_wait.task_list))); | 898 | /* We're supposed to be the only path putting the iocb back on the run |
| 899 | * list. If we find that the iocb is *back* on a wait queue already | ||
| 900 | * than retry has happened before we could queue the iocb. This also | ||
| 901 | * means that the retry could have completed and freed our iocb, no | ||
| 902 | * good. */ | ||
| 903 | BUG_ON((!list_empty(&iocb->ki_wait.task_list))); | ||
| 908 | 904 | ||
| 909 | spin_lock_irqsave(&ctx->ctx_lock, flags); | 905 | spin_lock_irqsave(&ctx->ctx_lock, flags); |
| 910 | run = __queue_kicked_iocb(iocb); | 906 | /* set this inside the lock so that we can't race with aio_run_iocb() |
| 907 | * testing it and putting the iocb on the run list under the lock */ | ||
| 908 | if (!kiocbTryKick(iocb)) | ||
| 909 | run = __queue_kicked_iocb(iocb); | ||
| 911 | spin_unlock_irqrestore(&ctx->ctx_lock, flags); | 910 | spin_unlock_irqrestore(&ctx->ctx_lock, flags); |
| 912 | if (run) | 911 | if (run) |
| 913 | aio_queue_work(ctx); | 912 | aio_queue_work(ctx); |
| @@ -930,10 +929,7 @@ void fastcall kick_iocb(struct kiocb *iocb) | |||
| 930 | return; | 929 | return; |
| 931 | } | 930 | } |
| 932 | 931 | ||
| 933 | /* If its already kicked we shouldn't queue it again */ | 932 | try_queue_kicked_iocb(iocb); |
| 934 | if (!kiocbTryKick(iocb)) { | ||
| 935 | queue_kicked_iocb(iocb); | ||
| 936 | } | ||
| 937 | } | 933 | } |
| 938 | EXPORT_SYMBOL(kick_iocb); | 934 | EXPORT_SYMBOL(kick_iocb); |
| 939 | 935 | ||
| @@ -1321,8 +1317,11 @@ asmlinkage long sys_io_destroy(aio_context_t ctx) | |||
| 1321 | } | 1317 | } |
| 1322 | 1318 | ||
| 1323 | /* | 1319 | /* |
| 1324 | * Default retry method for aio_read (also used for first time submit) | 1320 | * aio_p{read,write} are the default ki_retry methods for |
| 1325 | * Responsible for updating iocb state as retries progress | 1321 | * IO_CMD_P{READ,WRITE}. They maintains kiocb retry state around potentially |
| 1322 | * multiple calls to f_op->aio_read(). They loop around partial progress | ||
| 1323 | * instead of returning -EIOCBRETRY because they don't have the means to call | ||
| 1324 | * kick_iocb(). | ||
| 1326 | */ | 1325 | */ |
| 1327 | static ssize_t aio_pread(struct kiocb *iocb) | 1326 | static ssize_t aio_pread(struct kiocb *iocb) |
| 1328 | { | 1327 | { |
| @@ -1331,25 +1330,25 @@ static ssize_t aio_pread(struct kiocb *iocb) | |||
| 1331 | struct inode *inode = mapping->host; | 1330 | struct inode *inode = mapping->host; |
| 1332 | ssize_t ret = 0; | 1331 | ssize_t ret = 0; |
| 1333 | 1332 | ||
| 1334 | ret = file->f_op->aio_read(iocb, iocb->ki_buf, | 1333 | do { |
| 1335 | iocb->ki_left, iocb->ki_pos); | 1334 | ret = file->f_op->aio_read(iocb, iocb->ki_buf, |
| 1335 | iocb->ki_left, iocb->ki_pos); | ||
| 1336 | /* | ||
| 1337 | * Can't just depend on iocb->ki_left to determine | ||
| 1338 | * whether we are done. This may have been a short read. | ||
| 1339 | */ | ||
| 1340 | if (ret > 0) { | ||
| 1341 | iocb->ki_buf += ret; | ||
| 1342 | iocb->ki_left -= ret; | ||
| 1343 | } | ||
| 1336 | 1344 | ||
| 1337 | /* | ||
| 1338 | * Can't just depend on iocb->ki_left to determine | ||
| 1339 | * whether we are done. This may have been a short read. | ||
| 1340 | */ | ||
| 1341 | if (ret > 0) { | ||
| 1342 | iocb->ki_buf += ret; | ||
| 1343 | iocb->ki_left -= ret; | ||
| 1344 | /* | 1345 | /* |
| 1345 | * For pipes and sockets we return once we have | 1346 | * For pipes and sockets we return once we have some data; for |
| 1346 | * some data; for regular files we retry till we | 1347 | * regular files we retry till we complete the entire read or |
| 1347 | * complete the entire read or find that we can't | 1348 | * find that we can't read any more data (e.g short reads). |
| 1348 | * read any more data (e.g short reads). | ||
| 1349 | */ | 1349 | */ |
| 1350 | if (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode)) | 1350 | } while (ret > 0 && iocb->ki_left > 0 && |
| 1351 | ret = -EIOCBRETRY; | 1351 | !S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode)); |
| 1352 | } | ||
| 1353 | 1352 | ||
| 1354 | /* This means we must have transferred all that we could */ | 1353 | /* This means we must have transferred all that we could */ |
| 1355 | /* No need to retry anymore */ | 1354 | /* No need to retry anymore */ |
| @@ -1359,27 +1358,21 @@ static ssize_t aio_pread(struct kiocb *iocb) | |||
| 1359 | return ret; | 1358 | return ret; |
| 1360 | } | 1359 | } |
| 1361 | 1360 | ||
| 1362 | /* | 1361 | /* see aio_pread() */ |
| 1363 | * Default retry method for aio_write (also used for first time submit) | ||
| 1364 | * Responsible for updating iocb state as retries progress | ||
| 1365 | */ | ||
| 1366 | static ssize_t aio_pwrite(struct kiocb *iocb) | 1362 | static ssize_t aio_pwrite(struct kiocb *iocb) |
| 1367 | { | 1363 | { |
| 1368 | struct file *file = iocb->ki_filp; | 1364 | struct file *file = iocb->ki_filp; |
| 1369 | ssize_t ret = 0; | 1365 | ssize_t ret = 0; |
| 1370 | 1366 | ||
| 1371 | ret = file->f_op->aio_write(iocb, iocb->ki_buf, | 1367 | do { |
| 1372 | iocb->ki_left, iocb->ki_pos); | 1368 | ret = file->f_op->aio_write(iocb, iocb->ki_buf, |
| 1373 | 1369 | iocb->ki_left, iocb->ki_pos); | |
| 1374 | if (ret > 0) { | 1370 | if (ret > 0) { |
| 1375 | iocb->ki_buf += ret; | 1371 | iocb->ki_buf += ret; |
| 1376 | iocb->ki_left -= ret; | 1372 | iocb->ki_left -= ret; |
| 1377 | 1373 | } | |
| 1378 | ret = -EIOCBRETRY; | 1374 | } while (ret > 0 && iocb->ki_left > 0); |
| 1379 | } | ||
| 1380 | 1375 | ||
| 1381 | /* This means we must have transferred all that we could */ | ||
| 1382 | /* No need to retry anymore */ | ||
| 1383 | if ((ret == 0) || (iocb->ki_left == 0)) | 1376 | if ((ret == 0) || (iocb->ki_left == 0)) |
| 1384 | ret = iocb->ki_nbytes - iocb->ki_left; | 1377 | ret = iocb->ki_nbytes - iocb->ki_left; |
| 1385 | 1378 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8cc23e7d0d5d..1ebf7dafc1d7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -781,6 +781,8 @@ static int cifs_oplock_thread(void * dummyarg) | |||
| 781 | 781 | ||
| 782 | oplockThread = current; | 782 | oplockThread = current; |
| 783 | do { | 783 | do { |
| 784 | if (try_to_freeze()) | ||
| 785 | continue; | ||
| 784 | set_current_state(TASK_INTERRUPTIBLE); | 786 | set_current_state(TASK_INTERRUPTIBLE); |
| 785 | 787 | ||
| 786 | schedule_timeout(1*HZ); | 788 | schedule_timeout(1*HZ); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2335f14a1583..47360156cc54 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -344,6 +344,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | while (server->tcpStatus != CifsExiting) { | 346 | while (server->tcpStatus != CifsExiting) { |
| 347 | if (try_to_freeze()) | ||
| 348 | continue; | ||
| 347 | if (bigbuf == NULL) { | 349 | if (bigbuf == NULL) { |
| 348 | bigbuf = cifs_buf_get(); | 350 | bigbuf = cifs_buf_get(); |
| 349 | if(bigbuf == NULL) { | 351 | if(bigbuf == NULL) { |
diff --git a/fs/compat.c b/fs/compat.c index ac3fb9ed8eea..a719e158e002 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -44,6 +44,8 @@ | |||
| 44 | #include <linux/nfsd/syscall.h> | 44 | #include <linux/nfsd/syscall.h> |
| 45 | #include <linux/personality.h> | 45 | #include <linux/personality.h> |
| 46 | #include <linux/rwsem.h> | 46 | #include <linux/rwsem.h> |
| 47 | #include <linux/acct.h> | ||
| 48 | #include <linux/mm.h> | ||
| 47 | 49 | ||
| 48 | #include <net/sock.h> /* siocdevprivate_ioctl */ | 50 | #include <net/sock.h> /* siocdevprivate_ioctl */ |
| 49 | 51 | ||
| @@ -1487,6 +1489,8 @@ int compat_do_execve(char * filename, | |||
| 1487 | 1489 | ||
| 1488 | /* execve success */ | 1490 | /* execve success */ |
| 1489 | security_bprm_free(bprm); | 1491 | security_bprm_free(bprm); |
| 1492 | acct_update_integrals(current); | ||
| 1493 | update_mem_hiwater(current); | ||
| 1490 | kfree(bprm); | 1494 | kfree(bprm); |
| 1491 | return retval; | 1495 | return retval; |
| 1492 | } | 1496 | } |
diff --git a/fs/dcache.c b/fs/dcache.c index 7376b61269fb..fb10386c59be 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -102,7 +102,8 @@ static inline void dentry_iput(struct dentry * dentry) | |||
| 102 | list_del_init(&dentry->d_alias); | 102 | list_del_init(&dentry->d_alias); |
| 103 | spin_unlock(&dentry->d_lock); | 103 | spin_unlock(&dentry->d_lock); |
| 104 | spin_unlock(&dcache_lock); | 104 | spin_unlock(&dcache_lock); |
| 105 | fsnotify_inoderemove(inode); | 105 | if (!inode->i_nlink) |
| 106 | fsnotify_inoderemove(inode); | ||
| 106 | if (dentry->d_op && dentry->d_op->d_iput) | 107 | if (dentry->d_op && dentry->d_op->d_iput) |
| 107 | dentry->d_op->d_iput(dentry, inode); | 108 | dentry->d_op->d_iput(dentry, inode); |
| 108 | else | 109 | else |
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 6ab1dd0ca904..4284cd31eba6 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
| @@ -101,6 +101,10 @@ | |||
| 101 | /* Maximum number of poll wake up nests we are allowing */ | 101 | /* Maximum number of poll wake up nests we are allowing */ |
| 102 | #define EP_MAX_POLLWAKE_NESTS 4 | 102 | #define EP_MAX_POLLWAKE_NESTS 4 |
| 103 | 103 | ||
| 104 | /* Maximum msec timeout value storeable in a long int */ | ||
| 105 | #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ) | ||
| 106 | |||
| 107 | |||
| 104 | struct epoll_filefd { | 108 | struct epoll_filefd { |
| 105 | struct file *file; | 109 | struct file *file; |
| 106 | int fd; | 110 | int fd; |
| @@ -231,8 +235,9 @@ struct ep_pqueue { | |||
| 231 | 235 | ||
| 232 | static void ep_poll_safewake_init(struct poll_safewake *psw); | 236 | static void ep_poll_safewake_init(struct poll_safewake *psw); |
| 233 | static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq); | 237 | static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq); |
| 234 | static int ep_getfd(int *efd, struct inode **einode, struct file **efile); | 238 | static int ep_getfd(int *efd, struct inode **einode, struct file **efile, |
| 235 | static int ep_file_init(struct file *file); | 239 | struct eventpoll *ep); |
| 240 | static int ep_alloc(struct eventpoll **pep); | ||
| 236 | static void ep_free(struct eventpoll *ep); | 241 | static void ep_free(struct eventpoll *ep); |
| 237 | static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd); | 242 | static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd); |
| 238 | static void ep_use_epitem(struct epitem *epi); | 243 | static void ep_use_epitem(struct epitem *epi); |
| @@ -501,38 +506,37 @@ void eventpoll_release_file(struct file *file) | |||
| 501 | asmlinkage long sys_epoll_create(int size) | 506 | asmlinkage long sys_epoll_create(int size) |
| 502 | { | 507 | { |
| 503 | int error, fd; | 508 | int error, fd; |
| 509 | struct eventpoll *ep; | ||
| 504 | struct inode *inode; | 510 | struct inode *inode; |
| 505 | struct file *file; | 511 | struct file *file; |
| 506 | 512 | ||
| 507 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", | 513 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", |
| 508 | current, size)); | 514 | current, size)); |
| 509 | 515 | ||
| 510 | /* Sanity check on the size parameter */ | 516 | /* |
| 517 | * Sanity check on the size parameter, and create the internal data | ||
| 518 | * structure ( "struct eventpoll" ). | ||
| 519 | */ | ||
| 511 | error = -EINVAL; | 520 | error = -EINVAL; |
| 512 | if (size <= 0) | 521 | if (size <= 0 || (error = ep_alloc(&ep)) != 0) |
| 513 | goto eexit_1; | 522 | goto eexit_1; |
| 514 | 523 | ||
| 515 | /* | 524 | /* |
| 516 | * Creates all the items needed to setup an eventpoll file. That is, | 525 | * Creates all the items needed to setup an eventpoll file. That is, |
| 517 | * a file structure, and inode and a free file descriptor. | 526 | * a file structure, and inode and a free file descriptor. |
| 518 | */ | 527 | */ |
| 519 | error = ep_getfd(&fd, &inode, &file); | 528 | error = ep_getfd(&fd, &inode, &file, ep); |
| 520 | if (error) | ||
| 521 | goto eexit_1; | ||
| 522 | |||
| 523 | /* Setup the file internal data structure ( "struct eventpoll" ) */ | ||
| 524 | error = ep_file_init(file); | ||
| 525 | if (error) | 529 | if (error) |
| 526 | goto eexit_2; | 530 | goto eexit_2; |
| 527 | 531 | ||
| 528 | |||
| 529 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", | 532 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", |
| 530 | current, size, fd)); | 533 | current, size, fd)); |
| 531 | 534 | ||
| 532 | return fd; | 535 | return fd; |
| 533 | 536 | ||
| 534 | eexit_2: | 537 | eexit_2: |
| 535 | sys_close(fd); | 538 | ep_free(ep); |
| 539 | kfree(ep); | ||
| 536 | eexit_1: | 540 | eexit_1: |
| 537 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", | 541 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", |
| 538 | current, size, error)); | 542 | current, size, error)); |
| @@ -706,7 +710,8 @@ eexit_1: | |||
| 706 | /* | 710 | /* |
| 707 | * Creates the file descriptor to be used by the epoll interface. | 711 | * Creates the file descriptor to be used by the epoll interface. |
| 708 | */ | 712 | */ |
| 709 | static int ep_getfd(int *efd, struct inode **einode, struct file **efile) | 713 | static int ep_getfd(int *efd, struct inode **einode, struct file **efile, |
| 714 | struct eventpoll *ep) | ||
| 710 | { | 715 | { |
| 711 | struct qstr this; | 716 | struct qstr this; |
| 712 | char name[32]; | 717 | char name[32]; |
| @@ -756,7 +761,7 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile) | |||
| 756 | file->f_op = &eventpoll_fops; | 761 | file->f_op = &eventpoll_fops; |
| 757 | file->f_mode = FMODE_READ; | 762 | file->f_mode = FMODE_READ; |
| 758 | file->f_version = 0; | 763 | file->f_version = 0; |
| 759 | file->private_data = NULL; | 764 | file->private_data = ep; |
| 760 | 765 | ||
| 761 | /* Install the new setup file into the allocated fd. */ | 766 | /* Install the new setup file into the allocated fd. */ |
| 762 | fd_install(fd, file); | 767 | fd_install(fd, file); |
| @@ -777,14 +782,13 @@ eexit_1: | |||
| 777 | } | 782 | } |
| 778 | 783 | ||
| 779 | 784 | ||
| 780 | static int ep_file_init(struct file *file) | 785 | static int ep_alloc(struct eventpoll **pep) |
| 781 | { | 786 | { |
| 782 | struct eventpoll *ep; | 787 | struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL); |
| 783 | 788 | ||
| 784 | if (!(ep = kmalloc(sizeof(struct eventpoll), GFP_KERNEL))) | 789 | if (!ep) |
| 785 | return -ENOMEM; | 790 | return -ENOMEM; |
| 786 | 791 | ||
| 787 | memset(ep, 0, sizeof(*ep)); | ||
| 788 | rwlock_init(&ep->lock); | 792 | rwlock_init(&ep->lock); |
| 789 | init_rwsem(&ep->sem); | 793 | init_rwsem(&ep->sem); |
| 790 | init_waitqueue_head(&ep->wq); | 794 | init_waitqueue_head(&ep->wq); |
| @@ -792,9 +796,9 @@ static int ep_file_init(struct file *file) | |||
| 792 | INIT_LIST_HEAD(&ep->rdllist); | 796 | INIT_LIST_HEAD(&ep->rdllist); |
| 793 | ep->rbr = RB_ROOT; | 797 | ep->rbr = RB_ROOT; |
| 794 | 798 | ||
| 795 | file->private_data = ep; | 799 | *pep = ep; |
| 796 | 800 | ||
| 797 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_file_init() ep=%p\n", | 801 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n", |
| 798 | current, ep)); | 802 | current, ep)); |
| 799 | return 0; | 803 | return 0; |
| 800 | } | 804 | } |
| @@ -1506,8 +1510,8 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, | |||
| 1506 | * and the overflow condition. The passed timeout is in milliseconds, | 1510 | * and the overflow condition. The passed timeout is in milliseconds, |
| 1507 | * that why (t * HZ) / 1000. | 1511 | * that why (t * HZ) / 1000. |
| 1508 | */ | 1512 | */ |
| 1509 | jtimeout = timeout == -1 || timeout > (MAX_SCHEDULE_TIMEOUT - 1000) / HZ ? | 1513 | jtimeout = (timeout < 0 || timeout >= EP_MAX_MSTIMEO) ? |
| 1510 | MAX_SCHEDULE_TIMEOUT: (timeout * HZ + 999) / 1000; | 1514 | MAX_SCHEDULE_TIMEOUT : (timeout * HZ + 999) / 1000; |
| 1511 | 1515 | ||
| 1512 | retry: | 1516 | retry: |
| 1513 | write_lock_irqsave(&ep->lock, flags); | 1517 | write_lock_irqsave(&ep->lock, flags); |
| @@ -421,11 +421,6 @@ int setup_arg_pages(struct linux_binprm *bprm, | |||
| 421 | if (!mpnt) | 421 | if (!mpnt) |
| 422 | return -ENOMEM; | 422 | return -ENOMEM; |
| 423 | 423 | ||
| 424 | if (security_vm_enough_memory(arg_size >> PAGE_SHIFT)) { | ||
| 425 | kmem_cache_free(vm_area_cachep, mpnt); | ||
| 426 | return -ENOMEM; | ||
| 427 | } | ||
| 428 | |||
| 429 | memset(mpnt, 0, sizeof(*mpnt)); | 424 | memset(mpnt, 0, sizeof(*mpnt)); |
| 430 | 425 | ||
| 431 | down_write(&mm->mmap_sem); | 426 | down_write(&mm->mmap_sem); |
| @@ -745,8 +740,8 @@ static inline int de_thread(struct task_struct *tsk) | |||
| 745 | } | 740 | } |
| 746 | 741 | ||
| 747 | /* | 742 | /* |
| 748 | * Now there are really no other threads at all, | 743 | * There may be one thread left which is just exiting, |
| 749 | * so it's safe to stop telling them to kill themselves. | 744 | * but it's safe to stop telling the group to kill themselves. |
| 750 | */ | 745 | */ |
| 751 | sig->flags = 0; | 746 | sig->flags = 0; |
| 752 | 747 | ||
| @@ -785,7 +780,6 @@ no_thread_group: | |||
| 785 | kmem_cache_free(sighand_cachep, oldsighand); | 780 | kmem_cache_free(sighand_cachep, oldsighand); |
| 786 | } | 781 | } |
| 787 | 782 | ||
| 788 | BUG_ON(!thread_group_empty(current)); | ||
| 789 | BUG_ON(!thread_group_leader(current)); | 783 | BUG_ON(!thread_group_leader(current)); |
| 790 | return 0; | 784 | return 0; |
| 791 | } | 785 | } |
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index c8d07030c897..e2d6208633a7 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c | |||
| @@ -605,27 +605,28 @@ got: | |||
| 605 | insert_inode_hash(inode); | 605 | insert_inode_hash(inode); |
| 606 | 606 | ||
| 607 | if (DQUOT_ALLOC_INODE(inode)) { | 607 | if (DQUOT_ALLOC_INODE(inode)) { |
| 608 | DQUOT_DROP(inode); | ||
| 609 | err = -ENOSPC; | 608 | err = -ENOSPC; |
| 610 | goto fail2; | 609 | goto fail_drop; |
| 611 | } | 610 | } |
| 611 | |||
| 612 | err = ext2_init_acl(inode, dir); | 612 | err = ext2_init_acl(inode, dir); |
| 613 | if (err) { | 613 | if (err) |
| 614 | DQUOT_FREE_INODE(inode); | 614 | goto fail_free_drop; |
| 615 | DQUOT_DROP(inode); | 615 | |
| 616 | goto fail2; | ||
| 617 | } | ||
| 618 | err = ext2_init_security(inode,dir); | 616 | err = ext2_init_security(inode,dir); |
| 619 | if (err) { | 617 | if (err) |
| 620 | DQUOT_FREE_INODE(inode); | 618 | goto fail_free_drop; |
| 621 | goto fail2; | 619 | |
| 622 | } | ||
| 623 | mark_inode_dirty(inode); | 620 | mark_inode_dirty(inode); |
| 624 | ext2_debug("allocating inode %lu\n", inode->i_ino); | 621 | ext2_debug("allocating inode %lu\n", inode->i_ino); |
| 625 | ext2_preread_inode(inode); | 622 | ext2_preread_inode(inode); |
| 626 | return inode; | 623 | return inode; |
| 627 | 624 | ||
| 628 | fail2: | 625 | fail_free_drop: |
| 626 | DQUOT_FREE_INODE(inode); | ||
| 627 | |||
| 628 | fail_drop: | ||
| 629 | DQUOT_DROP(inode); | ||
| 629 | inode->i_flags |= S_NOQUOTA; | 630 | inode->i_flags |= S_NOQUOTA; |
| 630 | inode->i_nlink = 0; | 631 | inode->i_nlink = 0; |
| 631 | iput(inode); | 632 | iput(inode); |
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index e463dca008e4..0213db4911a2 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) | |||
| 1410 | unsigned long desc_count; | 1410 | unsigned long desc_count; |
| 1411 | struct ext3_group_desc *gdp; | 1411 | struct ext3_group_desc *gdp; |
| 1412 | int i; | 1412 | int i; |
| 1413 | unsigned long ngroups; | 1413 | unsigned long ngroups = EXT3_SB(sb)->s_groups_count; |
| 1414 | #ifdef EXT3FS_DEBUG | 1414 | #ifdef EXT3FS_DEBUG |
| 1415 | struct ext3_super_block *es; | 1415 | struct ext3_super_block *es; |
| 1416 | unsigned long bitmap_count, x; | 1416 | unsigned long bitmap_count, x; |
| @@ -1421,7 +1421,8 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) | |||
| 1421 | desc_count = 0; | 1421 | desc_count = 0; |
| 1422 | bitmap_count = 0; | 1422 | bitmap_count = 0; |
| 1423 | gdp = NULL; | 1423 | gdp = NULL; |
| 1424 | for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { | 1424 | |
| 1425 | for (i = 0; i < ngroups; i++) { | ||
| 1425 | gdp = ext3_get_group_desc(sb, i, NULL); | 1426 | gdp = ext3_get_group_desc(sb, i, NULL); |
| 1426 | if (!gdp) | 1427 | if (!gdp) |
| 1427 | continue; | 1428 | continue; |
| @@ -1443,7 +1444,6 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) | |||
| 1443 | return bitmap_count; | 1444 | return bitmap_count; |
| 1444 | #else | 1445 | #else |
| 1445 | desc_count = 0; | 1446 | desc_count = 0; |
| 1446 | ngroups = EXT3_SB(sb)->s_groups_count; | ||
| 1447 | smp_rmb(); | 1447 | smp_rmb(); |
| 1448 | for (i = 0; i < ngroups; i++) { | 1448 | for (i = 0; i < ngroups; i++) { |
| 1449 | gdp = ext3_get_group_desc(sb, i, NULL); | 1449 | gdp = ext3_get_group_desc(sb, i, NULL); |
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 96552769d039..6549945f9ac1 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c | |||
| @@ -597,27 +597,22 @@ got: | |||
| 597 | 597 | ||
| 598 | ret = inode; | 598 | ret = inode; |
| 599 | if(DQUOT_ALLOC_INODE(inode)) { | 599 | if(DQUOT_ALLOC_INODE(inode)) { |
| 600 | DQUOT_DROP(inode); | ||
| 601 | err = -EDQUOT; | 600 | err = -EDQUOT; |
| 602 | goto fail2; | 601 | goto fail_drop; |
| 603 | } | 602 | } |
| 603 | |||
| 604 | err = ext3_init_acl(handle, inode, dir); | 604 | err = ext3_init_acl(handle, inode, dir); |
| 605 | if (err) { | 605 | if (err) |
| 606 | DQUOT_FREE_INODE(inode); | 606 | goto fail_free_drop; |
| 607 | DQUOT_DROP(inode); | 607 | |
| 608 | goto fail2; | ||
| 609 | } | ||
| 610 | err = ext3_init_security(handle,inode, dir); | 608 | err = ext3_init_security(handle,inode, dir); |
| 611 | if (err) { | 609 | if (err) |
| 612 | DQUOT_FREE_INODE(inode); | 610 | goto fail_free_drop; |
| 613 | goto fail2; | 611 | |
| 614 | } | ||
| 615 | err = ext3_mark_inode_dirty(handle, inode); | 612 | err = ext3_mark_inode_dirty(handle, inode); |
| 616 | if (err) { | 613 | if (err) { |
| 617 | ext3_std_error(sb, err); | 614 | ext3_std_error(sb, err); |
| 618 | DQUOT_FREE_INODE(inode); | 615 | goto fail_free_drop; |
| 619 | DQUOT_DROP(inode); | ||
| 620 | goto fail2; | ||
| 621 | } | 616 | } |
| 622 | 617 | ||
| 623 | ext3_debug("allocating inode %lu\n", inode->i_ino); | 618 | ext3_debug("allocating inode %lu\n", inode->i_ino); |
| @@ -631,7 +626,11 @@ really_out: | |||
| 631 | brelse(bitmap_bh); | 626 | brelse(bitmap_bh); |
| 632 | return ret; | 627 | return ret; |
| 633 | 628 | ||
| 634 | fail2: | 629 | fail_free_drop: |
| 630 | DQUOT_FREE_INODE(inode); | ||
| 631 | |||
| 632 | fail_drop: | ||
| 633 | DQUOT_DROP(inode); | ||
| 635 | inode->i_flags |= S_NOQUOTA; | 634 | inode->i_flags |= S_NOQUOTA; |
| 636 | inode->i_nlink = 0; | 635 | inode->i_nlink = 0; |
| 637 | iput(inode); | 636 | iput(inode); |
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 2c9f81278d5d..57f79106267d 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, | |||
| 242 | i < sbi->s_itb_per_group; i++, bit++, block++) { | 242 | i < sbi->s_itb_per_group; i++, bit++, block++) { |
| 243 | struct buffer_head *it; | 243 | struct buffer_head *it; |
| 244 | 244 | ||
| 245 | ext3_debug("clear inode block %#04x (+%ld)\n", block, bit); | 245 | ext3_debug("clear inode block %#04lx (+%d)\n", block, bit); |
| 246 | if (IS_ERR(it = bclean(handle, sb, block))) { | 246 | if (IS_ERR(it = bclean(handle, sb, block))) { |
| 247 | err = PTR_ERR(it); | 247 | err = PTR_ERR(it); |
| 248 | goto exit_bh; | 248 | goto exit_bh; |
| @@ -643,8 +643,8 @@ static void update_backups(struct super_block *sb, | |||
| 643 | break; | 643 | break; |
| 644 | 644 | ||
| 645 | bh = sb_getblk(sb, group * bpg + blk_off); | 645 | bh = sb_getblk(sb, group * bpg + blk_off); |
| 646 | ext3_debug(sb, __FUNCTION__, "update metadata backup %#04lx\n", | 646 | ext3_debug("update metadata backup %#04lx\n", |
| 647 | bh->b_blocknr); | 647 | (unsigned long)bh->b_blocknr); |
| 648 | if ((err = ext3_journal_get_write_access(handle, bh))) | 648 | if ((err = ext3_journal_get_write_access(handle, bh))) |
| 649 | break; | 649 | break; |
| 650 | lock_buffer(bh); | 650 | lock_buffer(bh); |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index a93c3609025d..9e24ceb019fe 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
| @@ -512,15 +512,14 @@ static void ext3_clear_inode(struct inode *inode) | |||
| 512 | 512 | ||
| 513 | static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) | 513 | static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) |
| 514 | { | 514 | { |
| 515 | struct ext3_sb_info *sbi = EXT3_SB(vfs->mnt_sb); | 515 | struct super_block *sb = vfs->mnt_sb; |
| 516 | struct ext3_sb_info *sbi = EXT3_SB(sb); | ||
| 516 | 517 | ||
| 517 | if (sbi->s_mount_opt & EXT3_MOUNT_JOURNAL_DATA) | 518 | if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) |
| 518 | seq_puts(seq, ",data=journal"); | 519 | seq_puts(seq, ",data=journal"); |
| 519 | 520 | else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) | |
| 520 | if (sbi->s_mount_opt & EXT3_MOUNT_ORDERED_DATA) | ||
| 521 | seq_puts(seq, ",data=ordered"); | 521 | seq_puts(seq, ",data=ordered"); |
| 522 | 522 | else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) | |
| 523 | if (sbi->s_mount_opt & EXT3_MOUNT_WRITEBACK_DATA) | ||
| 524 | seq_puts(seq, ",data=writeback"); | 523 | seq_puts(seq, ",data=writeback"); |
| 525 | 524 | ||
| 526 | #if defined(CONFIG_QUOTA) | 525 | #if defined(CONFIG_QUOTA) |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 62ffa9139400..7134403d5be2 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -12,39 +12,6 @@ | |||
| 12 | #include <linux/smp_lock.h> | 12 | #include <linux/smp_lock.h> |
| 13 | #include <linux/buffer_head.h> | 13 | #include <linux/buffer_head.h> |
| 14 | 14 | ||
| 15 | static ssize_t fat_file_aio_write(struct kiocb *iocb, const char __user *buf, | ||
| 16 | size_t count, loff_t pos) | ||
| 17 | { | ||
| 18 | struct inode *inode = iocb->ki_filp->f_dentry->d_inode; | ||
| 19 | int retval; | ||
| 20 | |||
| 21 | retval = generic_file_aio_write(iocb, buf, count, pos); | ||
| 22 | if (retval > 0) { | ||
| 23 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | ||
| 24 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; | ||
| 25 | mark_inode_dirty(inode); | ||
| 26 | // check the locking rules | ||
| 27 | // if (IS_SYNC(inode)) | ||
| 28 | // fat_sync_inode(inode); | ||
| 29 | } | ||
| 30 | return retval; | ||
| 31 | } | ||
| 32 | |||
| 33 | static ssize_t fat_file_writev(struct file *filp, const struct iovec *iov, | ||
| 34 | unsigned long nr_segs, loff_t *ppos) | ||
| 35 | { | ||
| 36 | struct inode *inode = filp->f_dentry->d_inode; | ||
| 37 | int retval; | ||
| 38 | |||
| 39 | retval = generic_file_writev(filp, iov, nr_segs, ppos); | ||
| 40 | if (retval > 0) { | ||
| 41 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | ||
| 42 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; | ||
| 43 | mark_inode_dirty(inode); | ||
| 44 | } | ||
| 45 | return retval; | ||
| 46 | } | ||
| 47 | |||
| 48 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | 15 | int fat_generic_ioctl(struct inode *inode, struct file *filp, |
| 49 | unsigned int cmd, unsigned long arg) | 16 | unsigned int cmd, unsigned long arg) |
| 50 | { | 17 | { |
| @@ -148,9 +115,9 @@ struct file_operations fat_file_operations = { | |||
| 148 | .read = do_sync_read, | 115 | .read = do_sync_read, |
| 149 | .write = do_sync_write, | 116 | .write = do_sync_write, |
| 150 | .readv = generic_file_readv, | 117 | .readv = generic_file_readv, |
| 151 | .writev = fat_file_writev, | 118 | .writev = generic_file_writev, |
| 152 | .aio_read = generic_file_aio_read, | 119 | .aio_read = generic_file_aio_read, |
| 153 | .aio_write = fat_file_aio_write, | 120 | .aio_write = generic_file_aio_write, |
| 154 | .mmap = generic_file_mmap, | 121 | .mmap = generic_file_mmap, |
| 155 | .ioctl = fat_generic_ioctl, | 122 | .ioctl = fat_generic_ioctl, |
| 156 | .fsync = file_fsync, | 123 | .fsync = file_fsync, |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index a7cbe68e2259..e2effe2dc9b2 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
| @@ -102,6 +102,19 @@ static int fat_prepare_write(struct file *file, struct page *page, | |||
| 102 | &MSDOS_I(page->mapping->host)->mmu_private); | 102 | &MSDOS_I(page->mapping->host)->mmu_private); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static int fat_commit_write(struct file *file, struct page *page, | ||
| 106 | unsigned from, unsigned to) | ||
| 107 | { | ||
| 108 | struct inode *inode = page->mapping->host; | ||
| 109 | int err = generic_commit_write(file, page, from, to); | ||
| 110 | if (!err && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { | ||
| 111 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | ||
| 112 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; | ||
| 113 | mark_inode_dirty(inode); | ||
| 114 | } | ||
| 115 | return err; | ||
| 116 | } | ||
| 117 | |||
| 105 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) | 118 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) |
| 106 | { | 119 | { |
| 107 | return generic_block_bmap(mapping, block, fat_get_block); | 120 | return generic_block_bmap(mapping, block, fat_get_block); |
| @@ -112,7 +125,7 @@ static struct address_space_operations fat_aops = { | |||
| 112 | .writepage = fat_writepage, | 125 | .writepage = fat_writepage, |
| 113 | .sync_page = block_sync_page, | 126 | .sync_page = block_sync_page, |
| 114 | .prepare_write = fat_prepare_write, | 127 | .prepare_write = fat_prepare_write, |
| 115 | .commit_write = generic_commit_write, | 128 | .commit_write = fat_commit_write, |
| 116 | .bmap = _fat_bmap | 129 | .bmap = _fat_bmap |
| 117 | }; | 130 | }; |
| 118 | 131 | ||
| @@ -287,9 +300,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |||
| 287 | inode->i_blksize = sbi->cluster_size; | 300 | inode->i_blksize = sbi->cluster_size; |
| 288 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) | 301 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) |
| 289 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; | 302 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; |
| 290 | inode->i_mtime.tv_sec = inode->i_atime.tv_sec = | 303 | inode->i_mtime.tv_sec = |
| 291 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date)); | 304 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date)); |
| 292 | inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = 0; | 305 | inode->i_mtime.tv_nsec = 0; |
| 293 | if (sbi->options.isvfat) { | 306 | if (sbi->options.isvfat) { |
| 294 | int secs = de->ctime_cs / 100; | 307 | int secs = de->ctime_cs / 100; |
| 295 | int csecs = de->ctime_cs % 100; | 308 | int csecs = de->ctime_cs % 100; |
| @@ -297,8 +310,11 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |||
| 297 | date_dos2unix(le16_to_cpu(de->ctime), | 310 | date_dos2unix(le16_to_cpu(de->ctime), |
| 298 | le16_to_cpu(de->cdate)) + secs; | 311 | le16_to_cpu(de->cdate)) + secs; |
| 299 | inode->i_ctime.tv_nsec = csecs * 10000000; | 312 | inode->i_ctime.tv_nsec = csecs * 10000000; |
| 313 | inode->i_atime.tv_sec = | ||
| 314 | date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate)); | ||
| 315 | inode->i_atime.tv_nsec = 0; | ||
| 300 | } else | 316 | } else |
| 301 | inode->i_ctime = inode->i_mtime; | 317 | inode->i_ctime = inode->i_atime = inode->i_mtime; |
| 302 | 318 | ||
| 303 | return 0; | 319 | return 0; |
| 304 | } | 320 | } |
| @@ -500,7 +516,9 @@ retry: | |||
| 500 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); | 516 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); |
| 501 | fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date); | 517 | fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date); |
| 502 | if (sbi->options.isvfat) { | 518 | if (sbi->options.isvfat) { |
| 519 | __le16 atime; | ||
| 503 | fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate); | 520 | fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate); |
| 521 | fat_date_unix2dos(inode->i_atime.tv_sec,&atime,&raw_entry->adate); | ||
| 504 | raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + | 522 | raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + |
| 505 | inode->i_ctime.tv_nsec / 10000000; | 523 | inode->i_ctime.tv_nsec / 10000000; |
| 506 | } | 524 | } |
| @@ -69,13 +69,9 @@ void free_fd_array(struct file **array, int num) | |||
| 69 | 69 | ||
| 70 | static void __free_fdtable(struct fdtable *fdt) | 70 | static void __free_fdtable(struct fdtable *fdt) |
| 71 | { | 71 | { |
| 72 | int fdset_size, fdarray_size; | 72 | free_fdset(fdt->open_fds, fdt->max_fdset); |
| 73 | 73 | free_fdset(fdt->close_on_exec, fdt->max_fdset); | |
| 74 | fdset_size = fdt->max_fdset / 8; | 74 | free_fd_array(fdt->fd, fdt->max_fds); |
| 75 | fdarray_size = fdt->max_fds * sizeof(struct file *); | ||
| 76 | free_fdset(fdt->open_fds, fdset_size); | ||
| 77 | free_fdset(fdt->close_on_exec, fdset_size); | ||
| 78 | free_fd_array(fdt->fd, fdarray_size); | ||
| 79 | kfree(fdt); | 75 | kfree(fdt); |
| 80 | } | 76 | } |
| 81 | 77 | ||
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index e79e49b3eec7..29f1e9f6e85c 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, | |||
| 96 | fuse_lookup_init(req, dir, entry, &outarg); | 96 | fuse_lookup_init(req, dir, entry, &outarg); |
| 97 | request_send(fc, req); | 97 | request_send(fc, req); |
| 98 | err = req->out.h.error; | 98 | err = req->out.h.error; |
| 99 | if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID)) | ||
| 100 | err = -EIO; | ||
| 99 | if (!err) { | 101 | if (!err) { |
| 100 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 102 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
| 101 | &outarg.attr); | 103 | &outarg.attr); |
| @@ -152,6 +154,10 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
| 152 | fuse_put_request(fc, req); | 154 | fuse_put_request(fc, req); |
| 153 | return err; | 155 | return err; |
| 154 | } | 156 | } |
| 157 | if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) { | ||
| 158 | fuse_put_request(fc, req); | ||
| 159 | return -EIO; | ||
| 160 | } | ||
| 155 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 161 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
| 156 | &outarg.attr); | 162 | &outarg.attr); |
| 157 | if (!inode) { | 163 | if (!inode) { |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 6454022b0536..657ab11c173b 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) | |||
| 23 | struct fuse_file *ff; | 23 | struct fuse_file *ff; |
| 24 | int err; | 24 | int err; |
| 25 | 25 | ||
| 26 | /* VFS checks this, but only _after_ ->open() */ | ||
| 27 | if (file->f_flags & O_DIRECT) | ||
| 28 | return -EINVAL; | ||
| 29 | |||
| 26 | err = generic_file_open(inode, file); | 30 | err = generic_file_open(inode, file); |
| 27 | if (err) | 31 | if (err) |
| 28 | return err; | 32 | return err; |
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 59c5062cd63f..dd7113106269 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, | |||
| 793 | return(err); | 793 | return(err); |
| 794 | } | 794 | } |
| 795 | 795 | ||
| 796 | void hostfs_truncate(struct inode *ino) | ||
| 797 | { | ||
| 798 | not_implemented(); | ||
| 799 | } | ||
| 800 | |||
| 801 | int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd) | 796 | int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd) |
| 802 | { | 797 | { |
| 803 | char *name; | 798 | char *name; |
| @@ -894,7 +889,6 @@ static struct inode_operations hostfs_iops = { | |||
| 894 | .rmdir = hostfs_rmdir, | 889 | .rmdir = hostfs_rmdir, |
| 895 | .mknod = hostfs_mknod, | 890 | .mknod = hostfs_mknod, |
| 896 | .rename = hostfs_rename, | 891 | .rename = hostfs_rename, |
| 897 | .truncate = hostfs_truncate, | ||
| 898 | .permission = hostfs_permission, | 892 | .permission = hostfs_permission, |
| 899 | .setattr = hostfs_setattr, | 893 | .setattr = hostfs_setattr, |
| 900 | .getattr = hostfs_getattr, | 894 | .getattr = hostfs_getattr, |
| @@ -910,7 +904,6 @@ static struct inode_operations hostfs_dir_iops = { | |||
| 910 | .rmdir = hostfs_rmdir, | 904 | .rmdir = hostfs_rmdir, |
| 911 | .mknod = hostfs_mknod, | 905 | .mknod = hostfs_mknod, |
| 912 | .rename = hostfs_rename, | 906 | .rename = hostfs_rename, |
| 913 | .truncate = hostfs_truncate, | ||
| 914 | .permission = hostfs_permission, | 907 | .permission = hostfs_permission, |
| 915 | .setattr = hostfs_setattr, | 908 | .setattr = hostfs_setattr, |
| 916 | .getattr = hostfs_getattr, | 909 | .getattr = hostfs_getattr, |
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 0ec62d5310db..9f942ca8e4e3 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c | |||
| @@ -129,8 +129,7 @@ void jfs_delete_inode(struct inode *inode) | |||
| 129 | jfs_info("In jfs_delete_inode, inode = 0x%p", inode); | 129 | jfs_info("In jfs_delete_inode, inode = 0x%p", inode); |
| 130 | 130 | ||
| 131 | if (!is_bad_inode(inode) && | 131 | if (!is_bad_inode(inode) && |
| 132 | (JFS_IP(inode)->fileset == cpu_to_le32(FILESYSTEM_I))) { | 132 | (JFS_IP(inode)->fileset == FILESYSTEM_I)) { |
| 133 | |||
| 134 | truncate_inode_pages(&inode->i_data, 0); | 133 | truncate_inode_pages(&inode->i_data, 0); |
| 135 | 134 | ||
| 136 | if (test_cflag(COMMIT_Freewmap, inode)) | 135 | if (test_cflag(COMMIT_Freewmap, inode)) |
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index c739626f5bf1..eadf319bee22 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c | |||
| @@ -3055,7 +3055,7 @@ static int cntlz(u32 value) | |||
| 3055 | * RETURN VALUES: | 3055 | * RETURN VALUES: |
| 3056 | * log2 number of blocks | 3056 | * log2 number of blocks |
| 3057 | */ | 3057 | */ |
| 3058 | int blkstol2(s64 nb) | 3058 | static int blkstol2(s64 nb) |
| 3059 | { | 3059 | { |
| 3060 | int l2nb; | 3060 | int l2nb; |
| 3061 | s64 mask; /* meant to be signed */ | 3061 | s64 mask; /* meant to be signed */ |
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index c7a92f9deb2b..9b71ed2674fe 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, | |||
| 725 | else | 725 | else |
| 726 | tlck->flag = tlckINODELOCK; | 726 | tlck->flag = tlckINODELOCK; |
| 727 | 727 | ||
| 728 | if (S_ISDIR(ip->i_mode)) | ||
| 729 | tlck->flag |= tlckDIRECTORY; | ||
| 730 | |||
| 728 | tlck->type = 0; | 731 | tlck->type = 0; |
| 729 | 732 | ||
| 730 | /* bind the tlock and the page */ | 733 | /* bind the tlock and the page */ |
| @@ -1009,6 +1012,8 @@ struct tlock *txMaplock(tid_t tid, struct inode *ip, int type) | |||
| 1009 | 1012 | ||
| 1010 | /* bind the tlock and the object */ | 1013 | /* bind the tlock and the object */ |
| 1011 | tlck->flag = tlckINODELOCK; | 1014 | tlck->flag = tlckINODELOCK; |
| 1015 | if (S_ISDIR(ip->i_mode)) | ||
| 1016 | tlck->flag |= tlckDIRECTORY; | ||
| 1012 | tlck->ip = ip; | 1017 | tlck->ip = ip; |
| 1013 | tlck->mp = NULL; | 1018 | tlck->mp = NULL; |
| 1014 | 1019 | ||
| @@ -1077,6 +1082,8 @@ struct linelock *txLinelock(struct linelock * tlock) | |||
| 1077 | linelock->flag = tlckLINELOCK; | 1082 | linelock->flag = tlckLINELOCK; |
| 1078 | linelock->maxcnt = TLOCKLONG; | 1083 | linelock->maxcnt = TLOCKLONG; |
| 1079 | linelock->index = 0; | 1084 | linelock->index = 0; |
| 1085 | if (tlck->flag & tlckDIRECTORY) | ||
| 1086 | linelock->flag |= tlckDIRECTORY; | ||
| 1080 | 1087 | ||
| 1081 | /* append linelock after tlock */ | 1088 | /* append linelock after tlock */ |
| 1082 | linelock->next = tlock->next; | 1089 | linelock->next = tlock->next; |
| @@ -2070,8 +2077,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
| 2070 | * | 2077 | * |
| 2071 | * function: log from maplock of freed data extents; | 2078 | * function: log from maplock of freed data extents; |
| 2072 | */ | 2079 | */ |
| 2073 | void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | 2080 | static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, |
| 2074 | struct tlock * tlck) | 2081 | struct tlock * tlck) |
| 2075 | { | 2082 | { |
| 2076 | struct pxd_lock *pxdlock; | 2083 | struct pxd_lock *pxdlock; |
| 2077 | int i, nlock; | 2084 | int i, nlock; |
| @@ -2209,7 +2216,7 @@ void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea) | |||
| 2209 | * function: synchronously write pages locked by transaction | 2216 | * function: synchronously write pages locked by transaction |
| 2210 | * after txLog() but before txUpdateMap(); | 2217 | * after txLog() but before txUpdateMap(); |
| 2211 | */ | 2218 | */ |
| 2212 | void txForce(struct tblock * tblk) | 2219 | static void txForce(struct tblock * tblk) |
| 2213 | { | 2220 | { |
| 2214 | struct tlock *tlck; | 2221 | struct tlock *tlck; |
| 2215 | lid_t lid, next; | 2222 | lid_t lid, next; |
| @@ -2358,7 +2365,7 @@ static void txUpdateMap(struct tblock * tblk) | |||
| 2358 | */ | 2365 | */ |
| 2359 | else { /* (maplock->flag & mlckFREE) */ | 2366 | else { /* (maplock->flag & mlckFREE) */ |
| 2360 | 2367 | ||
| 2361 | if (S_ISDIR(tlck->ip->i_mode)) | 2368 | if (tlck->flag & tlckDIRECTORY) |
| 2362 | txFreeMap(ipimap, maplock, | 2369 | txFreeMap(ipimap, maplock, |
| 2363 | tblk, COMMIT_PWMAP); | 2370 | tblk, COMMIT_PWMAP); |
| 2364 | else | 2371 | else |
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h index 59ad0f6b7231..0e4dc4514c47 100644 --- a/fs/jfs/jfs_txnmgr.h +++ b/fs/jfs/jfs_txnmgr.h | |||
| @@ -122,6 +122,7 @@ extern struct tlock *TxLock; /* transaction lock table */ | |||
| 122 | #define tlckLOG 0x0800 | 122 | #define tlckLOG 0x0800 |
| 123 | /* updateMap state */ | 123 | /* updateMap state */ |
| 124 | #define tlckUPDATEMAP 0x0080 | 124 | #define tlckUPDATEMAP 0x0080 |
| 125 | #define tlckDIRECTORY 0x0040 | ||
| 125 | /* freeLock state */ | 126 | /* freeLock state */ |
| 126 | #define tlckFREELOCK 0x0008 | 127 | #define tlckFREELOCK 0x0008 |
| 127 | #define tlckWRITEPAGE 0x0004 | 128 | #define tlckWRITEPAGE 0x0004 |
diff --git a/fs/locks.c b/fs/locks.c index c2c09b4798d6..f7daa5f48949 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -124,6 +124,7 @@ | |||
| 124 | #include <linux/smp_lock.h> | 124 | #include <linux/smp_lock.h> |
| 125 | #include <linux/syscalls.h> | 125 | #include <linux/syscalls.h> |
| 126 | #include <linux/time.h> | 126 | #include <linux/time.h> |
| 127 | #include <linux/rcupdate.h> | ||
| 127 | 128 | ||
| 128 | #include <asm/semaphore.h> | 129 | #include <asm/semaphore.h> |
| 129 | #include <asm/uaccess.h> | 130 | #include <asm/uaccess.h> |
| @@ -2205,6 +2206,7 @@ void steal_locks(fl_owner_t from) | |||
| 2205 | 2206 | ||
| 2206 | lock_kernel(); | 2207 | lock_kernel(); |
| 2207 | j = 0; | 2208 | j = 0; |
| 2209 | rcu_read_lock(); | ||
| 2208 | fdt = files_fdtable(files); | 2210 | fdt = files_fdtable(files); |
| 2209 | for (;;) { | 2211 | for (;;) { |
| 2210 | unsigned long set; | 2212 | unsigned long set; |
| @@ -2222,6 +2224,7 @@ void steal_locks(fl_owner_t from) | |||
| 2222 | set >>= 1; | 2224 | set >>= 1; |
| 2223 | } | 2225 | } |
| 2224 | } | 2226 | } |
| 2227 | rcu_read_unlock(); | ||
| 2225 | unlock_kernel(); | 2228 | unlock_kernel(); |
| 2226 | } | 2229 | } |
| 2227 | EXPORT_SYMBOL(steal_locks); | 2230 | EXPORT_SYMBOL(steal_locks); |
diff --git a/fs/namei.c b/fs/namei.c index 21d85f1ac839..043d587216b5 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1048,7 +1048,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata | |||
| 1048 | out: | 1048 | out: |
| 1049 | if (unlikely(current->audit_context | 1049 | if (unlikely(current->audit_context |
| 1050 | && nd && nd->dentry && nd->dentry->d_inode)) | 1050 | && nd && nd->dentry && nd->dentry->d_inode)) |
| 1051 | audit_inode(name, nd->dentry->d_inode); | 1051 | audit_inode(name, nd->dentry->d_inode, flags); |
| 1052 | return retval; | 1052 | return retval; |
| 1053 | } | 1053 | } |
| 1054 | 1054 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 6ceb1d471f20..9758ebd49905 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -184,14 +184,13 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
| 184 | { | 184 | { |
| 185 | unlock_page(req->wb_page); | 185 | unlock_page(req->wb_page); |
| 186 | 186 | ||
| 187 | nfs_clear_request(req); | ||
| 188 | nfs_release_request(req); | ||
| 189 | |||
| 190 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | 187 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", |
| 191 | req->wb_context->dentry->d_inode->i_sb->s_id, | 188 | req->wb_context->dentry->d_inode->i_sb->s_id, |
| 192 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | 189 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), |
| 193 | req->wb_bytes, | 190 | req->wb_bytes, |
| 194 | (long long)req_offset(req)); | 191 | (long long)req_offset(req)); |
| 192 | nfs_clear_request(req); | ||
| 193 | nfs_release_request(req); | ||
| 195 | } | 194 | } |
| 196 | 195 | ||
| 197 | /* | 196 | /* |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index e08edc17c6a0..361b4007d4a0 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
| @@ -162,7 +162,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ | |||
| 162 | 162 | ||
| 163 | 163 | ||
| 164 | static inline int | 164 | static inline int |
| 165 | nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 165 | nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) |
| 166 | { | 166 | { |
| 167 | int status; | 167 | int status; |
| 168 | dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", | 168 | dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", |
| @@ -238,8 +238,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
| 238 | */ | 238 | */ |
| 239 | status = nfsd4_process_open2(rqstp, current_fh, open); | 239 | status = nfsd4_process_open2(rqstp, current_fh, open); |
| 240 | out: | 240 | out: |
| 241 | if (open->op_stateowner) | 241 | if (open->op_stateowner) { |
| 242 | nfs4_get_stateowner(open->op_stateowner); | 242 | nfs4_get_stateowner(open->op_stateowner); |
| 243 | *replay_owner = open->op_stateowner; | ||
| 244 | } | ||
| 243 | nfs4_unlock_state(); | 245 | nfs4_unlock_state(); |
| 244 | return status; | 246 | return status; |
| 245 | } | 247 | } |
| @@ -809,8 +811,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
| 809 | op->status = nfsd4_access(rqstp, current_fh, &op->u.access); | 811 | op->status = nfsd4_access(rqstp, current_fh, &op->u.access); |
| 810 | break; | 812 | break; |
| 811 | case OP_CLOSE: | 813 | case OP_CLOSE: |
| 812 | op->status = nfsd4_close(rqstp, current_fh, &op->u.close); | 814 | op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner); |
| 813 | replay_owner = op->u.close.cl_stateowner; | ||
| 814 | break; | 815 | break; |
| 815 | case OP_COMMIT: | 816 | case OP_COMMIT: |
| 816 | op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit); | 817 | op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit); |
| @@ -831,15 +832,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
| 831 | op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); | 832 | op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); |
| 832 | break; | 833 | break; |
| 833 | case OP_LOCK: | 834 | case OP_LOCK: |
| 834 | op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock); | 835 | op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner); |
| 835 | replay_owner = op->u.lock.lk_stateowner; | ||
| 836 | break; | 836 | break; |
| 837 | case OP_LOCKT: | 837 | case OP_LOCKT: |
| 838 | op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt); | 838 | op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt); |
| 839 | break; | 839 | break; |
| 840 | case OP_LOCKU: | 840 | case OP_LOCKU: |
| 841 | op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku); | 841 | op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner); |
| 842 | replay_owner = op->u.locku.lu_stateowner; | ||
| 843 | break; | 842 | break; |
| 844 | case OP_LOOKUP: | 843 | case OP_LOOKUP: |
| 845 | op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup); | 844 | op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup); |
| @@ -853,16 +852,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
| 853 | op->status = nfs_ok; | 852 | op->status = nfs_ok; |
| 854 | break; | 853 | break; |
| 855 | case OP_OPEN: | 854 | case OP_OPEN: |
| 856 | op->status = nfsd4_open(rqstp, current_fh, &op->u.open); | 855 | op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner); |
| 857 | replay_owner = op->u.open.op_stateowner; | ||
| 858 | break; | 856 | break; |
| 859 | case OP_OPEN_CONFIRM: | 857 | case OP_OPEN_CONFIRM: |
| 860 | op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm); | 858 | op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner); |
| 861 | replay_owner = op->u.open_confirm.oc_stateowner; | ||
| 862 | break; | 859 | break; |
| 863 | case OP_OPEN_DOWNGRADE: | 860 | case OP_OPEN_DOWNGRADE: |
| 864 | op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade); | 861 | op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner); |
| 865 | replay_owner = op->u.open_downgrade.od_stateowner; | ||
| 866 | break; | 862 | break; |
| 867 | case OP_PUTFH: | 863 | case OP_PUTFH: |
| 868 | op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh); | 864 | op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b83f8fb441e1..6bbefd06f10d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -624,7 +624,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | |||
| 624 | cb->cb_ident = se->se_callback_ident; | 624 | cb->cb_ident = se->se_callback_ident; |
| 625 | return; | 625 | return; |
| 626 | out_err: | 626 | out_err: |
| 627 | printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " | 627 | dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " |
| 628 | "will not receive delegations\n", | 628 | "will not receive delegations\n", |
| 629 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | 629 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); |
| 630 | 630 | ||
| @@ -678,13 +678,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
| 678 | int status; | 678 | int status; |
| 679 | char dname[HEXDIR_LEN]; | 679 | char dname[HEXDIR_LEN]; |
| 680 | 680 | ||
| 681 | status = nfserr_inval; | ||
| 682 | if (!check_name(clname)) | 681 | if (!check_name(clname)) |
| 683 | goto out; | 682 | return nfserr_inval; |
| 684 | 683 | ||
| 685 | status = nfs4_make_rec_clidname(dname, &clname); | 684 | status = nfs4_make_rec_clidname(dname, &clname); |
| 686 | if (status) | 685 | if (status) |
| 687 | goto out; | 686 | return status; |
| 688 | 687 | ||
| 689 | /* | 688 | /* |
| 690 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | 689 | * XXX The Duplicate Request Cache (DRC) has been checked (??) |
| @@ -2014,7 +2013,7 @@ STALE_STATEID(stateid_t *stateid) | |||
| 2014 | { | 2013 | { |
| 2015 | if (stateid->si_boot == boot_time) | 2014 | if (stateid->si_boot == boot_time) |
| 2016 | return 0; | 2015 | return 0; |
| 2017 | printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", | 2016 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", |
| 2018 | stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, | 2017 | stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, |
| 2019 | stateid->si_generation); | 2018 | stateid->si_generation); |
| 2020 | return 1; | 2019 | return 1; |
| @@ -2275,7 +2274,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
| 2275 | 2274 | ||
| 2276 | check_replay: | 2275 | check_replay: |
| 2277 | if (seqid == sop->so_seqid - 1) { | 2276 | if (seqid == sop->so_seqid - 1) { |
| 2278 | printk("NFSD: preprocess_seqid_op: retransmission?\n"); | 2277 | dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); |
| 2279 | /* indicate replay to calling function */ | 2278 | /* indicate replay to calling function */ |
| 2280 | return NFSERR_REPLAY_ME; | 2279 | return NFSERR_REPLAY_ME; |
| 2281 | } | 2280 | } |
| @@ -2286,7 +2285,7 @@ check_replay: | |||
| 2286 | } | 2285 | } |
| 2287 | 2286 | ||
| 2288 | int | 2287 | int |
| 2289 | nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc) | 2288 | nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner) |
| 2290 | { | 2289 | { |
| 2291 | int status; | 2290 | int status; |
| 2292 | struct nfs4_stateowner *sop; | 2291 | struct nfs4_stateowner *sop; |
| @@ -2320,8 +2319,10 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs | |||
| 2320 | 2319 | ||
| 2321 | nfsd4_create_clid_dir(sop->so_client); | 2320 | nfsd4_create_clid_dir(sop->so_client); |
| 2322 | out: | 2321 | out: |
| 2323 | if (oc->oc_stateowner) | 2322 | if (oc->oc_stateowner) { |
| 2324 | nfs4_get_stateowner(oc->oc_stateowner); | 2323 | nfs4_get_stateowner(oc->oc_stateowner); |
| 2324 | *replay_owner = oc->oc_stateowner; | ||
| 2325 | } | ||
| 2325 | nfs4_unlock_state(); | 2326 | nfs4_unlock_state(); |
| 2326 | return status; | 2327 | return status; |
| 2327 | } | 2328 | } |
| @@ -2352,7 +2353,7 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) | |||
| 2352 | } | 2353 | } |
| 2353 | 2354 | ||
| 2354 | int | 2355 | int |
| 2355 | nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od) | 2356 | nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner) |
| 2356 | { | 2357 | { |
| 2357 | int status; | 2358 | int status; |
| 2358 | struct nfs4_stateid *stp; | 2359 | struct nfs4_stateid *stp; |
| @@ -2394,8 +2395,10 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n | |||
| 2394 | memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2395 | memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); |
| 2395 | status = nfs_ok; | 2396 | status = nfs_ok; |
| 2396 | out: | 2397 | out: |
| 2397 | if (od->od_stateowner) | 2398 | if (od->od_stateowner) { |
| 2398 | nfs4_get_stateowner(od->od_stateowner); | 2399 | nfs4_get_stateowner(od->od_stateowner); |
| 2400 | *replay_owner = od->od_stateowner; | ||
| 2401 | } | ||
| 2399 | nfs4_unlock_state(); | 2402 | nfs4_unlock_state(); |
| 2400 | return status; | 2403 | return status; |
| 2401 | } | 2404 | } |
| @@ -2404,7 +2407,7 @@ out: | |||
| 2404 | * nfs4_unlock_state() called after encode | 2407 | * nfs4_unlock_state() called after encode |
| 2405 | */ | 2408 | */ |
| 2406 | int | 2409 | int |
| 2407 | nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close) | 2410 | nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner) |
| 2408 | { | 2411 | { |
| 2409 | int status; | 2412 | int status; |
| 2410 | struct nfs4_stateid *stp; | 2413 | struct nfs4_stateid *stp; |
| @@ -2430,8 +2433,10 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos | |||
| 2430 | /* release_state_owner() calls nfsd_close() if needed */ | 2433 | /* release_state_owner() calls nfsd_close() if needed */ |
| 2431 | release_state_owner(stp, OPEN_STATE); | 2434 | release_state_owner(stp, OPEN_STATE); |
| 2432 | out: | 2435 | out: |
| 2433 | if (close->cl_stateowner) | 2436 | if (close->cl_stateowner) { |
| 2434 | nfs4_get_stateowner(close->cl_stateowner); | 2437 | nfs4_get_stateowner(close->cl_stateowner); |
| 2438 | *replay_owner = close->cl_stateowner; | ||
| 2439 | } | ||
| 2435 | nfs4_unlock_state(); | 2440 | nfs4_unlock_state(); |
| 2436 | return status; | 2441 | return status; |
| 2437 | } | 2442 | } |
| @@ -2500,8 +2505,7 @@ find_stateid(stateid_t *stid, int flags) | |||
| 2500 | (local->st_stateid.si_fileid == f_id)) | 2505 | (local->st_stateid.si_fileid == f_id)) |
| 2501 | return local; | 2506 | return local; |
| 2502 | } | 2507 | } |
| 2503 | } else | 2508 | } |
| 2504 | printk("NFSD: find_stateid: ERROR: no state flag\n"); | ||
| 2505 | return NULL; | 2509 | return NULL; |
| 2506 | } | 2510 | } |
| 2507 | 2511 | ||
| @@ -2624,7 +2628,9 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
| 2624 | sop->so_is_open_owner = 0; | 2628 | sop->so_is_open_owner = 0; |
| 2625 | sop->so_id = current_ownerid++; | 2629 | sop->so_id = current_ownerid++; |
| 2626 | sop->so_client = clp; | 2630 | sop->so_client = clp; |
| 2627 | sop->so_seqid = lock->lk_new_lock_seqid; | 2631 | /* It is the openowner seqid that will be incremented in encode in the |
| 2632 | * case of new lockowners; so increment the lock seqid manually: */ | ||
| 2633 | sop->so_seqid = lock->lk_new_lock_seqid + 1; | ||
| 2628 | sop->so_confirmed = 1; | 2634 | sop->so_confirmed = 1; |
| 2629 | rp = &sop->so_replay; | 2635 | rp = &sop->so_replay; |
| 2630 | rp->rp_status = NFSERR_SERVERFAULT; | 2636 | rp->rp_status = NFSERR_SERVERFAULT; |
| @@ -2676,9 +2682,10 @@ check_lock_length(u64 offset, u64 length) | |||
| 2676 | * LOCK operation | 2682 | * LOCK operation |
| 2677 | */ | 2683 | */ |
| 2678 | int | 2684 | int |
| 2679 | nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) | 2685 | nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner) |
| 2680 | { | 2686 | { |
| 2681 | struct nfs4_stateowner *open_sop = NULL; | 2687 | struct nfs4_stateowner *open_sop = NULL; |
| 2688 | struct nfs4_stateowner *lock_sop = NULL; | ||
| 2682 | struct nfs4_stateid *lock_stp; | 2689 | struct nfs4_stateid *lock_stp; |
| 2683 | struct file *filp; | 2690 | struct file *filp; |
| 2684 | struct file_lock file_lock; | 2691 | struct file_lock file_lock; |
| @@ -2705,19 +2712,19 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2705 | struct nfs4_file *fp; | 2712 | struct nfs4_file *fp; |
| 2706 | 2713 | ||
| 2707 | status = nfserr_stale_clientid; | 2714 | status = nfserr_stale_clientid; |
| 2708 | if (STALE_CLIENTID(&lock->lk_new_clientid)) { | 2715 | if (STALE_CLIENTID(&lock->lk_new_clientid)) |
| 2709 | printk("NFSD: nfsd4_lock: clientid is stale!\n"); | ||
| 2710 | goto out; | 2716 | goto out; |
| 2711 | } | ||
| 2712 | 2717 | ||
| 2713 | /* validate and update open stateid and open seqid */ | 2718 | /* validate and update open stateid and open seqid */ |
| 2714 | status = nfs4_preprocess_seqid_op(current_fh, | 2719 | status = nfs4_preprocess_seqid_op(current_fh, |
| 2715 | lock->lk_new_open_seqid, | 2720 | lock->lk_new_open_seqid, |
| 2716 | &lock->lk_new_open_stateid, | 2721 | &lock->lk_new_open_stateid, |
| 2717 | CHECK_FH | OPEN_STATE, | 2722 | CHECK_FH | OPEN_STATE, |
| 2718 | &open_sop, &open_stp, lock); | 2723 | &lock->lk_stateowner, &open_stp, |
| 2724 | lock); | ||
| 2719 | if (status) | 2725 | if (status) |
| 2720 | goto out; | 2726 | goto out; |
| 2727 | open_sop = lock->lk_stateowner; | ||
| 2721 | /* create lockowner and lock stateid */ | 2728 | /* create lockowner and lock stateid */ |
| 2722 | fp = open_stp->st_file; | 2729 | fp = open_stp->st_file; |
| 2723 | strhashval = lock_ownerstr_hashval(fp->fi_inode, | 2730 | strhashval = lock_ownerstr_hashval(fp->fi_inode, |
| @@ -2727,16 +2734,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2727 | * the same file, or should they just be allowed (and | 2734 | * the same file, or should they just be allowed (and |
| 2728 | * create new stateids)? */ | 2735 | * create new stateids)? */ |
| 2729 | status = nfserr_resource; | 2736 | status = nfserr_resource; |
| 2730 | if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) | 2737 | lock_sop = alloc_init_lock_stateowner(strhashval, |
| 2738 | open_sop->so_client, open_stp, lock); | ||
| 2739 | if (lock_sop == NULL) | ||
| 2731 | goto out; | 2740 | goto out; |
| 2732 | if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, | 2741 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); |
| 2733 | fp, open_stp)) == NULL) { | 2742 | if (lock_stp == NULL) { |
| 2734 | release_stateowner(lock->lk_stateowner); | 2743 | release_stateowner(lock_sop); |
| 2735 | lock->lk_stateowner = NULL; | ||
| 2736 | goto out; | 2744 | goto out; |
| 2737 | } | 2745 | } |
| 2738 | /* bump the open seqid used to create the lock */ | ||
| 2739 | open_sop->so_seqid++; | ||
| 2740 | } else { | 2746 | } else { |
| 2741 | /* lock (lock owner + lock stateid) already exists */ | 2747 | /* lock (lock owner + lock stateid) already exists */ |
| 2742 | status = nfs4_preprocess_seqid_op(current_fh, | 2748 | status = nfs4_preprocess_seqid_op(current_fh, |
| @@ -2746,12 +2752,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2746 | &lock->lk_stateowner, &lock_stp, lock); | 2752 | &lock->lk_stateowner, &lock_stp, lock); |
| 2747 | if (status) | 2753 | if (status) |
| 2748 | goto out; | 2754 | goto out; |
| 2755 | lock_sop = lock->lk_stateowner; | ||
| 2749 | } | 2756 | } |
| 2750 | /* lock->lk_stateowner and lock_stp have been created or found */ | 2757 | /* lock->lk_stateowner and lock_stp have been created or found */ |
| 2751 | filp = lock_stp->st_vfs_file; | 2758 | filp = lock_stp->st_vfs_file; |
| 2752 | 2759 | ||
| 2753 | if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { | 2760 | if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { |
| 2754 | printk("NFSD: nfsd4_lock: permission denied!\n"); | 2761 | dprintk("NFSD: nfsd4_lock: permission denied!\n"); |
| 2755 | goto out; | 2762 | goto out; |
| 2756 | } | 2763 | } |
| 2757 | 2764 | ||
| @@ -2776,7 +2783,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2776 | status = nfserr_inval; | 2783 | status = nfserr_inval; |
| 2777 | goto out; | 2784 | goto out; |
| 2778 | } | 2785 | } |
| 2779 | file_lock.fl_owner = (fl_owner_t) lock->lk_stateowner; | 2786 | file_lock.fl_owner = (fl_owner_t)lock_sop; |
| 2780 | file_lock.fl_pid = current->tgid; | 2787 | file_lock.fl_pid = current->tgid; |
| 2781 | file_lock.fl_file = filp; | 2788 | file_lock.fl_file = filp; |
| 2782 | file_lock.fl_flags = FL_POSIX; | 2789 | file_lock.fl_flags = FL_POSIX; |
| @@ -2832,14 +2839,13 @@ out_destroy_new_stateid: | |||
| 2832 | * An error encountered after instantiation of the new | 2839 | * An error encountered after instantiation of the new |
| 2833 | * stateid has forced us to destroy it. | 2840 | * stateid has forced us to destroy it. |
| 2834 | */ | 2841 | */ |
| 2835 | if (!seqid_mutating_err(status)) | ||
| 2836 | open_sop->so_seqid--; | ||
| 2837 | |||
| 2838 | release_state_owner(lock_stp, LOCK_STATE); | 2842 | release_state_owner(lock_stp, LOCK_STATE); |
| 2839 | } | 2843 | } |
| 2840 | out: | 2844 | out: |
| 2841 | if (lock->lk_stateowner) | 2845 | if (lock->lk_stateowner) { |
| 2842 | nfs4_get_stateowner(lock->lk_stateowner); | 2846 | nfs4_get_stateowner(lock->lk_stateowner); |
| 2847 | *replay_owner = lock->lk_stateowner; | ||
| 2848 | } | ||
| 2843 | nfs4_unlock_state(); | 2849 | nfs4_unlock_state(); |
| 2844 | return status; | 2850 | return status; |
| 2845 | } | 2851 | } |
| @@ -2866,13 +2872,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2866 | nfs4_lock_state(); | 2872 | nfs4_lock_state(); |
| 2867 | 2873 | ||
| 2868 | status = nfserr_stale_clientid; | 2874 | status = nfserr_stale_clientid; |
| 2869 | if (STALE_CLIENTID(&lockt->lt_clientid)) { | 2875 | if (STALE_CLIENTID(&lockt->lt_clientid)) |
| 2870 | printk("NFSD: nfsd4_lockt: clientid is stale!\n"); | ||
| 2871 | goto out; | 2876 | goto out; |
| 2872 | } | ||
| 2873 | 2877 | ||
| 2874 | if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) { | 2878 | if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) { |
| 2875 | printk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); | 2879 | dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); |
| 2876 | if (status == nfserr_symlink) | 2880 | if (status == nfserr_symlink) |
| 2877 | status = nfserr_inval; | 2881 | status = nfserr_inval; |
| 2878 | goto out; | 2882 | goto out; |
| @@ -2930,7 +2934,7 @@ out: | |||
| 2930 | } | 2934 | } |
| 2931 | 2935 | ||
| 2932 | int | 2936 | int |
| 2933 | nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku) | 2937 | nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner) |
| 2934 | { | 2938 | { |
| 2935 | struct nfs4_stateid *stp; | 2939 | struct nfs4_stateid *stp; |
| 2936 | struct file *filp = NULL; | 2940 | struct file *filp = NULL; |
| @@ -2976,7 +2980,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2976 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | 2980 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) |
| 2977 | file_lock.fl_ops->fl_release_private(&file_lock); | 2981 | file_lock.fl_ops->fl_release_private(&file_lock); |
| 2978 | if (status) { | 2982 | if (status) { |
| 2979 | printk("NFSD: nfs4_locku: posix_lock_file failed!\n"); | 2983 | dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); |
| 2980 | goto out_nfserr; | 2984 | goto out_nfserr; |
| 2981 | } | 2985 | } |
| 2982 | /* | 2986 | /* |
| @@ -2986,8 +2990,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2986 | memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2990 | memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); |
| 2987 | 2991 | ||
| 2988 | out: | 2992 | out: |
| 2989 | if (locku->lu_stateowner) | 2993 | if (locku->lu_stateowner) { |
| 2990 | nfs4_get_stateowner(locku->lu_stateowner); | 2994 | nfs4_get_stateowner(locku->lu_stateowner); |
| 2995 | *replay_owner = locku->lu_stateowner; | ||
| 2996 | } | ||
| 2991 | nfs4_unlock_state(); | 2997 | nfs4_unlock_state(); |
| 2992 | return status; | 2998 | return status; |
| 2993 | 2999 | ||
| @@ -3036,10 +3042,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * | |||
| 3036 | /* XXX check for lease expiration */ | 3042 | /* XXX check for lease expiration */ |
| 3037 | 3043 | ||
| 3038 | status = nfserr_stale_clientid; | 3044 | status = nfserr_stale_clientid; |
| 3039 | if (STALE_CLIENTID(clid)) { | 3045 | if (STALE_CLIENTID(clid)) |
| 3040 | printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n"); | ||
| 3041 | return status; | 3046 | return status; |
| 3042 | } | ||
| 3043 | 3047 | ||
| 3044 | nfs4_lock_state(); | 3048 | nfs4_lock_state(); |
| 3045 | 3049 | ||
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 49eafbdb15c1..83f3322765cd 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
| @@ -29,7 +29,8 @@ ToDo/Notes: | |||
| 29 | The Windows boot will run chkdsk and then reboot. The user can then | 29 | The Windows boot will run chkdsk and then reboot. The user can then |
| 30 | immediately boot into Linux rather than having to do a full Windows | 30 | immediately boot into Linux rather than having to do a full Windows |
| 31 | boot first before rebooting into Linux and we will recognize such a | 31 | boot first before rebooting into Linux and we will recognize such a |
| 32 | journal and empty it as it is clean by definition. | 32 | journal and empty it as it is clean by definition. Note, this only |
| 33 | works if chkdsk left the journal in an obviously clean state. | ||
| 33 | - Support journals ($LogFile) with only one restart page as well as | 34 | - Support journals ($LogFile) with only one restart page as well as |
| 34 | journals with two different restart pages. We sanity check both and | 35 | journals with two different restart pages. We sanity check both and |
| 35 | either use the only sane one or the more recent one of the two in the | 36 | either use the only sane one or the more recent one of the two in the |
| @@ -92,6 +93,15 @@ ToDo/Notes: | |||
| 92 | an octal number to conform to how chmod(1) works, too. Thanks to | 93 | an octal number to conform to how chmod(1) works, too. Thanks to |
| 93 | Giuseppe Bilotta and Horst von Brand for pointing out the errors of | 94 | Giuseppe Bilotta and Horst von Brand for pointing out the errors of |
| 94 | my ways. | 95 | my ways. |
| 96 | - Fix various bugs in the runlist merging code. (Based on libntfs | ||
| 97 | changes by Richard Russon.) | ||
| 98 | - Fix sparse warnings that have crept in over time. | ||
| 99 | - Change ntfs_cluster_free() to require a write locked runlist on entry | ||
| 100 | since we otherwise get into a lock reversal deadlock if a read locked | ||
| 101 | runlist is passed in. In the process also change it to take an ntfs | ||
| 102 | inode instead of a vfs inode as parameter. | ||
| 103 | - Fix the definition of the CHKD ntfs record magic. It had an off by | ||
| 104 | two error causing it to be CHKB instead of CHKD. | ||
| 95 | 105 | ||
| 96 | 2.1.23 - Implement extension of resident files and make writing safe as well as | 106 | 2.1.23 - Implement extension of resident files and make writing safe as well as |
| 97 | many bug fixes, cleanups, and enhancements... | 107 | many bug fixes, cleanups, and enhancements... |
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index b6cc8cf24626..5e80c07c6a4d 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c | |||
| @@ -59,39 +59,49 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
| 59 | unsigned long flags; | 59 | unsigned long flags; |
| 60 | struct buffer_head *first, *tmp; | 60 | struct buffer_head *first, *tmp; |
| 61 | struct page *page; | 61 | struct page *page; |
| 62 | struct inode *vi; | ||
| 62 | ntfs_inode *ni; | 63 | ntfs_inode *ni; |
| 63 | int page_uptodate = 1; | 64 | int page_uptodate = 1; |
| 64 | 65 | ||
| 65 | page = bh->b_page; | 66 | page = bh->b_page; |
| 66 | ni = NTFS_I(page->mapping->host); | 67 | vi = page->mapping->host; |
| 68 | ni = NTFS_I(vi); | ||
| 67 | 69 | ||
| 68 | if (likely(uptodate)) { | 70 | if (likely(uptodate)) { |
| 69 | s64 file_ofs, initialized_size; | 71 | loff_t i_size; |
| 72 | s64 file_ofs, init_size; | ||
| 70 | 73 | ||
| 71 | set_buffer_uptodate(bh); | 74 | set_buffer_uptodate(bh); |
| 72 | 75 | ||
| 73 | file_ofs = ((s64)page->index << PAGE_CACHE_SHIFT) + | 76 | file_ofs = ((s64)page->index << PAGE_CACHE_SHIFT) + |
| 74 | bh_offset(bh); | 77 | bh_offset(bh); |
| 75 | read_lock_irqsave(&ni->size_lock, flags); | 78 | read_lock_irqsave(&ni->size_lock, flags); |
| 76 | initialized_size = ni->initialized_size; | 79 | init_size = ni->initialized_size; |
| 80 | i_size = i_size_read(vi); | ||
| 77 | read_unlock_irqrestore(&ni->size_lock, flags); | 81 | read_unlock_irqrestore(&ni->size_lock, flags); |
| 82 | if (unlikely(init_size > i_size)) { | ||
| 83 | /* Race with shrinking truncate. */ | ||
| 84 | init_size = i_size; | ||
| 85 | } | ||
| 78 | /* Check for the current buffer head overflowing. */ | 86 | /* Check for the current buffer head overflowing. */ |
| 79 | if (file_ofs + bh->b_size > initialized_size) { | 87 | if (unlikely(file_ofs + bh->b_size > init_size)) { |
| 80 | char *addr; | 88 | u8 *kaddr; |
| 81 | int ofs = 0; | 89 | int ofs; |
| 82 | 90 | ||
| 83 | if (file_ofs < initialized_size) | 91 | ofs = 0; |
| 84 | ofs = initialized_size - file_ofs; | 92 | if (file_ofs < init_size) |
| 85 | addr = kmap_atomic(page, KM_BIO_SRC_IRQ); | 93 | ofs = init_size - file_ofs; |
| 86 | memset(addr + bh_offset(bh) + ofs, 0, bh->b_size - ofs); | 94 | kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); |
| 95 | memset(kaddr + bh_offset(bh) + ofs, 0, | ||
| 96 | bh->b_size - ofs); | ||
| 97 | kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); | ||
| 87 | flush_dcache_page(page); | 98 | flush_dcache_page(page); |
| 88 | kunmap_atomic(addr, KM_BIO_SRC_IRQ); | ||
| 89 | } | 99 | } |
| 90 | } else { | 100 | } else { |
| 91 | clear_buffer_uptodate(bh); | 101 | clear_buffer_uptodate(bh); |
| 92 | SetPageError(page); | 102 | SetPageError(page); |
| 93 | ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %llu.", | 103 | ntfs_error(ni->vol->sb, "Buffer I/O error, logical block " |
| 94 | (unsigned long long)bh->b_blocknr); | 104 | "0x%llx.", (unsigned long long)bh->b_blocknr); |
| 95 | } | 105 | } |
| 96 | first = page_buffers(page); | 106 | first = page_buffers(page); |
| 97 | local_irq_save(flags); | 107 | local_irq_save(flags); |
| @@ -124,7 +134,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
| 124 | if (likely(page_uptodate && !PageError(page))) | 134 | if (likely(page_uptodate && !PageError(page))) |
| 125 | SetPageUptodate(page); | 135 | SetPageUptodate(page); |
| 126 | } else { | 136 | } else { |
| 127 | char *addr; | 137 | u8 *kaddr; |
| 128 | unsigned int i, recs; | 138 | unsigned int i, recs; |
| 129 | u32 rec_size; | 139 | u32 rec_size; |
| 130 | 140 | ||
| @@ -132,12 +142,12 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) | |||
| 132 | recs = PAGE_CACHE_SIZE / rec_size; | 142 | recs = PAGE_CACHE_SIZE / rec_size; |
| 133 | /* Should have been verified before we got here... */ | 143 | /* Should have been verified before we got here... */ |
| 134 | BUG_ON(!recs); | 144 | BUG_ON(!recs); |
| 135 | addr = kmap_atomic(page, KM_BIO_SRC_IRQ); | 145 | kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); |
| 136 | for (i = 0; i < recs; i++) | 146 | for (i = 0; i < recs; i++) |
| 137 | post_read_mst_fixup((NTFS_RECORD*)(addr + | 147 | post_read_mst_fixup((NTFS_RECORD*)(kaddr + |
| 138 | i * rec_size), rec_size); | 148 | i * rec_size), rec_size); |
| 149 | kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); | ||
| 139 | flush_dcache_page(page); | 150 | flush_dcache_page(page); |
| 140 | kunmap_atomic(addr, KM_BIO_SRC_IRQ); | ||
| 141 | if (likely(page_uptodate && !PageError(page))) | 151 | if (likely(page_uptodate && !PageError(page))) |
| 142 | SetPageUptodate(page); | 152 | SetPageUptodate(page); |
| 143 | } | 153 | } |
| @@ -168,8 +178,11 @@ still_busy: | |||
| 168 | */ | 178 | */ |
| 169 | static int ntfs_read_block(struct page *page) | 179 | static int ntfs_read_block(struct page *page) |
| 170 | { | 180 | { |
| 181 | loff_t i_size; | ||
| 171 | VCN vcn; | 182 | VCN vcn; |
| 172 | LCN lcn; | 183 | LCN lcn; |
| 184 | s64 init_size; | ||
| 185 | struct inode *vi; | ||
| 173 | ntfs_inode *ni; | 186 | ntfs_inode *ni; |
| 174 | ntfs_volume *vol; | 187 | ntfs_volume *vol; |
| 175 | runlist_element *rl; | 188 | runlist_element *rl; |
| @@ -180,7 +193,8 @@ static int ntfs_read_block(struct page *page) | |||
| 180 | int i, nr; | 193 | int i, nr; |
| 181 | unsigned char blocksize_bits; | 194 | unsigned char blocksize_bits; |
| 182 | 195 | ||
| 183 | ni = NTFS_I(page->mapping->host); | 196 | vi = page->mapping->host; |
| 197 | ni = NTFS_I(vi); | ||
| 184 | vol = ni->vol; | 198 | vol = ni->vol; |
| 185 | 199 | ||
| 186 | /* $MFT/$DATA must have its complete runlist in memory at all times. */ | 200 | /* $MFT/$DATA must have its complete runlist in memory at all times. */ |
| @@ -199,11 +213,28 @@ static int ntfs_read_block(struct page *page) | |||
| 199 | bh = head = page_buffers(page); | 213 | bh = head = page_buffers(page); |
| 200 | BUG_ON(!bh); | 214 | BUG_ON(!bh); |
| 201 | 215 | ||
| 216 | /* | ||
| 217 | * We may be racing with truncate. To avoid some of the problems we | ||
| 218 | * now take a snapshot of the various sizes and use those for the whole | ||
| 219 | * of the function. In case of an extending truncate it just means we | ||
| 220 | * may leave some buffers unmapped which are now allocated. This is | ||
| 221 | * not a problem since these buffers will just get mapped when a write | ||
| 222 | * occurs. In case of a shrinking truncate, we will detect this later | ||
| 223 | * on due to the runlist being incomplete and if the page is being | ||
| 224 | * fully truncated, truncate will throw it away as soon as we unlock | ||
| 225 | * it so no need to worry what we do with it. | ||
| 226 | */ | ||
| 202 | iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); | 227 | iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); |
| 203 | read_lock_irqsave(&ni->size_lock, flags); | 228 | read_lock_irqsave(&ni->size_lock, flags); |
| 204 | lblock = (ni->allocated_size + blocksize - 1) >> blocksize_bits; | 229 | lblock = (ni->allocated_size + blocksize - 1) >> blocksize_bits; |
| 205 | zblock = (ni->initialized_size + blocksize - 1) >> blocksize_bits; | 230 | init_size = ni->initialized_size; |
| 231 | i_size = i_size_read(vi); | ||
| 206 | read_unlock_irqrestore(&ni->size_lock, flags); | 232 | read_unlock_irqrestore(&ni->size_lock, flags); |
| 233 | if (unlikely(init_size > i_size)) { | ||
| 234 | /* Race with shrinking truncate. */ | ||
| 235 | init_size = i_size; | ||
| 236 | } | ||
| 237 | zblock = (init_size + blocksize - 1) >> blocksize_bits; | ||
| 207 | 238 | ||
| 208 | /* Loop through all the buffers in the page. */ | 239 | /* Loop through all the buffers in the page. */ |
| 209 | rl = NULL; | 240 | rl = NULL; |
| @@ -366,6 +397,8 @@ handle_zblock: | |||
| 366 | */ | 397 | */ |
| 367 | static int ntfs_readpage(struct file *file, struct page *page) | 398 | static int ntfs_readpage(struct file *file, struct page *page) |
| 368 | { | 399 | { |
| 400 | loff_t i_size; | ||
| 401 | struct inode *vi; | ||
| 369 | ntfs_inode *ni, *base_ni; | 402 | ntfs_inode *ni, *base_ni; |
| 370 | u8 *kaddr; | 403 | u8 *kaddr; |
| 371 | ntfs_attr_search_ctx *ctx; | 404 | ntfs_attr_search_ctx *ctx; |
| @@ -384,14 +417,17 @@ retry_readpage: | |||
| 384 | unlock_page(page); | 417 | unlock_page(page); |
| 385 | return 0; | 418 | return 0; |
| 386 | } | 419 | } |
| 387 | ni = NTFS_I(page->mapping->host); | 420 | vi = page->mapping->host; |
| 421 | ni = NTFS_I(vi); | ||
| 388 | /* | 422 | /* |
| 389 | * Only $DATA attributes can be encrypted and only unnamed $DATA | 423 | * Only $DATA attributes can be encrypted and only unnamed $DATA |
| 390 | * attributes can be compressed. Index root can have the flags set but | 424 | * attributes can be compressed. Index root can have the flags set but |
| 391 | * this means to create compressed/encrypted files, not that the | 425 | * this means to create compressed/encrypted files, not that the |
| 392 | * attribute is compressed/encrypted. | 426 | * attribute is compressed/encrypted. Note we need to check for |
| 427 | * AT_INDEX_ALLOCATION since this is the type of both directory and | ||
| 428 | * index inodes. | ||
| 393 | */ | 429 | */ |
| 394 | if (ni->type != AT_INDEX_ROOT) { | 430 | if (ni->type != AT_INDEX_ALLOCATION) { |
| 395 | /* If attribute is encrypted, deny access, just like NT4. */ | 431 | /* If attribute is encrypted, deny access, just like NT4. */ |
| 396 | if (NInoEncrypted(ni)) { | 432 | if (NInoEncrypted(ni)) { |
| 397 | BUG_ON(ni->type != AT_DATA); | 433 | BUG_ON(ni->type != AT_DATA); |
| @@ -456,7 +492,12 @@ retry_readpage: | |||
| 456 | read_lock_irqsave(&ni->size_lock, flags); | 492 | read_lock_irqsave(&ni->size_lock, flags); |
| 457 | if (unlikely(attr_len > ni->initialized_size)) | 493 | if (unlikely(attr_len > ni->initialized_size)) |
| 458 | attr_len = ni->initialized_size; | 494 | attr_len = ni->initialized_size; |
| 495 | i_size = i_size_read(vi); | ||
| 459 | read_unlock_irqrestore(&ni->size_lock, flags); | 496 | read_unlock_irqrestore(&ni->size_lock, flags); |
| 497 | if (unlikely(attr_len > i_size)) { | ||
| 498 | /* Race with shrinking truncate. */ | ||
| 499 | attr_len = i_size; | ||
| 500 | } | ||
| 460 | kaddr = kmap_atomic(page, KM_USER0); | 501 | kaddr = kmap_atomic(page, KM_USER0); |
| 461 | /* Copy the data to the page. */ | 502 | /* Copy the data to the page. */ |
| 462 | memcpy(kaddr, (u8*)ctx->attr + | 503 | memcpy(kaddr, (u8*)ctx->attr + |
| @@ -1341,9 +1382,11 @@ retry_writepage: | |||
| 1341 | * Only $DATA attributes can be encrypted and only unnamed $DATA | 1382 | * Only $DATA attributes can be encrypted and only unnamed $DATA |
| 1342 | * attributes can be compressed. Index root can have the flags set but | 1383 | * attributes can be compressed. Index root can have the flags set but |
| 1343 | * this means to create compressed/encrypted files, not that the | 1384 | * this means to create compressed/encrypted files, not that the |
| 1344 | * attribute is compressed/encrypted. | 1385 | * attribute is compressed/encrypted. Note we need to check for |
| 1386 | * AT_INDEX_ALLOCATION since this is the type of both directory and | ||
| 1387 | * index inodes. | ||
| 1345 | */ | 1388 | */ |
| 1346 | if (ni->type != AT_INDEX_ROOT) { | 1389 | if (ni->type != AT_INDEX_ALLOCATION) { |
| 1347 | /* If file is encrypted, deny access, just like NT4. */ | 1390 | /* If file is encrypted, deny access, just like NT4. */ |
| 1348 | if (NInoEncrypted(ni)) { | 1391 | if (NInoEncrypted(ni)) { |
| 1349 | unlock_page(page); | 1392 | unlock_page(page); |
| @@ -1379,8 +1422,8 @@ retry_writepage: | |||
| 1379 | unsigned int ofs = i_size & ~PAGE_CACHE_MASK; | 1422 | unsigned int ofs = i_size & ~PAGE_CACHE_MASK; |
| 1380 | kaddr = kmap_atomic(page, KM_USER0); | 1423 | kaddr = kmap_atomic(page, KM_USER0); |
| 1381 | memset(kaddr + ofs, 0, PAGE_CACHE_SIZE - ofs); | 1424 | memset(kaddr + ofs, 0, PAGE_CACHE_SIZE - ofs); |
| 1382 | flush_dcache_page(page); | ||
| 1383 | kunmap_atomic(kaddr, KM_USER0); | 1425 | kunmap_atomic(kaddr, KM_USER0); |
| 1426 | flush_dcache_page(page); | ||
| 1384 | } | 1427 | } |
| 1385 | /* Handle mst protected attributes. */ | 1428 | /* Handle mst protected attributes. */ |
| 1386 | if (NInoMstProtected(ni)) | 1429 | if (NInoMstProtected(ni)) |
| @@ -1443,34 +1486,33 @@ retry_writepage: | |||
| 1443 | BUG_ON(PageWriteback(page)); | 1486 | BUG_ON(PageWriteback(page)); |
| 1444 | set_page_writeback(page); | 1487 | set_page_writeback(page); |
| 1445 | unlock_page(page); | 1488 | unlock_page(page); |
| 1446 | /* | ||
| 1447 | * Here, we do not need to zero the out of bounds area everytime | ||
| 1448 | * because the below memcpy() already takes care of the | ||
| 1449 | * mmap-at-end-of-file requirements. If the file is converted to a | ||
| 1450 | * non-resident one, then the code path use is switched to the | ||
| 1451 | * non-resident one where the zeroing happens on each ntfs_writepage() | ||
| 1452 | * invocation. | ||
| 1453 | */ | ||
| 1454 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); | 1489 | attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); |
| 1455 | i_size = i_size_read(vi); | 1490 | i_size = i_size_read(vi); |
| 1456 | if (unlikely(attr_len > i_size)) { | 1491 | if (unlikely(attr_len > i_size)) { |
| 1492 | /* Race with shrinking truncate or a failed truncate. */ | ||
| 1457 | attr_len = i_size; | 1493 | attr_len = i_size; |
| 1458 | ctx->attr->data.resident.value_length = cpu_to_le32(attr_len); | 1494 | /* |
| 1495 | * If the truncate failed, fix it up now. If a concurrent | ||
| 1496 | * truncate, we do its job, so it does not have to do anything. | ||
| 1497 | */ | ||
| 1498 | err = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, | ||
| 1499 | attr_len); | ||
| 1500 | /* Shrinking cannot fail. */ | ||
| 1501 | BUG_ON(err); | ||
| 1459 | } | 1502 | } |
| 1460 | kaddr = kmap_atomic(page, KM_USER0); | 1503 | kaddr = kmap_atomic(page, KM_USER0); |
| 1461 | /* Copy the data from the page to the mft record. */ | 1504 | /* Copy the data from the page to the mft record. */ |
| 1462 | memcpy((u8*)ctx->attr + | 1505 | memcpy((u8*)ctx->attr + |
| 1463 | le16_to_cpu(ctx->attr->data.resident.value_offset), | 1506 | le16_to_cpu(ctx->attr->data.resident.value_offset), |
| 1464 | kaddr, attr_len); | 1507 | kaddr, attr_len); |
| 1465 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
| 1466 | /* Zero out of bounds area in the page cache page. */ | 1508 | /* Zero out of bounds area in the page cache page. */ |
| 1467 | memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); | 1509 | memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); |
| 1468 | flush_dcache_page(page); | ||
| 1469 | kunmap_atomic(kaddr, KM_USER0); | 1510 | kunmap_atomic(kaddr, KM_USER0); |
| 1470 | 1511 | flush_dcache_mft_record_page(ctx->ntfs_ino); | |
| 1512 | flush_dcache_page(page); | ||
| 1513 | /* We are done with the page. */ | ||
| 1471 | end_page_writeback(page); | 1514 | end_page_writeback(page); |
| 1472 | 1515 | /* Finally, mark the mft record dirty, so it gets written back. */ | |
| 1473 | /* Mark the mft record dirty, so it gets written back. */ | ||
| 1474 | mark_mft_record_dirty(ctx->ntfs_ino); | 1516 | mark_mft_record_dirty(ctx->ntfs_ino); |
| 1475 | ntfs_attr_put_search_ctx(ctx); | 1517 | ntfs_attr_put_search_ctx(ctx); |
| 1476 | unmap_mft_record(base_ni); | 1518 | unmap_mft_record(base_ni); |
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index dc4bbe3acf5c..7ec045131808 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
| @@ -1166,6 +1166,8 @@ err_out: | |||
| 1166 | * | 1166 | * |
| 1167 | * Return 0 on success and -errno on error. In the error case, the inode will | 1167 | * Return 0 on success and -errno on error. In the error case, the inode will |
| 1168 | * have had make_bad_inode() executed on it. | 1168 | * have had make_bad_inode() executed on it. |
| 1169 | * | ||
| 1170 | * Note this cannot be called for AT_INDEX_ALLOCATION. | ||
| 1169 | */ | 1171 | */ |
| 1170 | static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | 1172 | static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) |
| 1171 | { | 1173 | { |
| @@ -1242,8 +1244,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
| 1242 | } | 1244 | } |
| 1243 | } | 1245 | } |
| 1244 | /* | 1246 | /* |
| 1245 | * The encryption flag set in an index root just means to | 1247 | * The compressed/sparse flag set in an index root just means |
| 1246 | * compress all files. | 1248 | * to compress all files. |
| 1247 | */ | 1249 | */ |
| 1248 | if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { | 1250 | if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { |
| 1249 | ntfs_error(vi->i_sb, "Found mst protected attribute " | 1251 | ntfs_error(vi->i_sb, "Found mst protected attribute " |
| @@ -1319,8 +1321,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) | |||
| 1319 | "the mapping pairs array."); | 1321 | "the mapping pairs array."); |
| 1320 | goto unm_err_out; | 1322 | goto unm_err_out; |
| 1321 | } | 1323 | } |
| 1322 | if ((NInoCompressed(ni) || NInoSparse(ni)) && | 1324 | if (NInoCompressed(ni) || NInoSparse(ni)) { |
| 1323 | ni->type != AT_INDEX_ROOT) { | ||
| 1324 | if (a->data.non_resident.compression_unit != 4) { | 1325 | if (a->data.non_resident.compression_unit != 4) { |
| 1325 | ntfs_error(vi->i_sb, "Found nonstandard " | 1326 | ntfs_error(vi->i_sb, "Found nonstandard " |
| 1326 | "compression unit (%u instead " | 1327 | "compression unit (%u instead " |
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index 609ad1728ce4..01f2dfa39cec 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h | |||
| @@ -123,7 +123,7 @@ enum { | |||
| 123 | magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */ | 123 | magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */ |
| 124 | 124 | ||
| 125 | /* Found in $LogFile/$DATA. (May be found in $MFT/$DATA, also?) */ | 125 | /* Found in $LogFile/$DATA. (May be found in $MFT/$DATA, also?) */ |
| 126 | magic_CHKD = const_cpu_to_le32(0x424b4843), /* Modified by chkdsk. */ | 126 | magic_CHKD = const_cpu_to_le32(0x444b4843), /* Modified by chkdsk. */ |
| 127 | 127 | ||
| 128 | /* Found in all ntfs record containing records. */ | 128 | /* Found in all ntfs record containing records. */ |
| 129 | magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector | 129 | magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector |
| @@ -308,10 +308,8 @@ typedef le16 MFT_RECORD_FLAGS; | |||
| 308 | * The _LE versions are to be applied on little endian MFT_REFs. | 308 | * The _LE versions are to be applied on little endian MFT_REFs. |
| 309 | * Note: The _LE versions will return a CPU endian formatted value! | 309 | * Note: The _LE versions will return a CPU endian formatted value! |
| 310 | */ | 310 | */ |
| 311 | typedef enum { | 311 | #define MFT_REF_MASK_CPU 0x0000ffffffffffffULL |
| 312 | MFT_REF_MASK_CPU = 0x0000ffffffffffffULL, | 312 | #define MFT_REF_MASK_LE const_cpu_to_le64(0x0000ffffffffffffULL) |
| 313 | MFT_REF_MASK_LE = const_cpu_to_le64(0x0000ffffffffffffULL), | ||
| 314 | } MFT_REF_CONSTS; | ||
| 315 | 313 | ||
| 316 | typedef u64 MFT_REF; | 314 | typedef u64 MFT_REF; |
| 317 | typedef le64 leMFT_REF; | 315 | typedef le64 leMFT_REF; |
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c index 7b5934290685..5af3bf0b7eee 100644 --- a/fs/ntfs/lcnalloc.c +++ b/fs/ntfs/lcnalloc.c | |||
| @@ -779,14 +779,13 @@ out: | |||
| 779 | 779 | ||
| 780 | /** | 780 | /** |
| 781 | * __ntfs_cluster_free - free clusters on an ntfs volume | 781 | * __ntfs_cluster_free - free clusters on an ntfs volume |
| 782 | * @vi: vfs inode whose runlist describes the clusters to free | 782 | * @ni: ntfs inode whose runlist describes the clusters to free |
| 783 | * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters | 783 | * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters |
| 784 | * @count: number of clusters to free or -1 for all clusters | 784 | * @count: number of clusters to free or -1 for all clusters |
| 785 | * @write_locked: true if the runlist is locked for writing | ||
| 786 | * @is_rollback: true if this is a rollback operation | 785 | * @is_rollback: true if this is a rollback operation |
| 787 | * | 786 | * |
| 788 | * Free @count clusters starting at the cluster @start_vcn in the runlist | 787 | * Free @count clusters starting at the cluster @start_vcn in the runlist |
| 789 | * described by the vfs inode @vi. | 788 | * described by the vfs inode @ni. |
| 790 | * | 789 | * |
| 791 | * If @count is -1, all clusters from @start_vcn to the end of the runlist are | 790 | * If @count is -1, all clusters from @start_vcn to the end of the runlist are |
| 792 | * deallocated. Thus, to completely free all clusters in a runlist, use | 791 | * deallocated. Thus, to completely free all clusters in a runlist, use |
| @@ -801,31 +800,28 @@ out: | |||
| 801 | * Return the number of deallocated clusters (not counting sparse ones) on | 800 | * Return the number of deallocated clusters (not counting sparse ones) on |
| 802 | * success and -errno on error. | 801 | * success and -errno on error. |
| 803 | * | 802 | * |
| 804 | * Locking: - The runlist described by @vi must be locked on entry and is | 803 | * Locking: - The runlist described by @ni must be locked for writing on entry |
| 805 | * locked on return. Note if the runlist is locked for reading the | 804 | * and is locked on return. Note the runlist may be modified when |
| 806 | * lock may be dropped and reacquired. Note the runlist may be | 805 | * needed runlist fragments need to be mapped. |
| 807 | * modified when needed runlist fragments need to be mapped. | ||
| 808 | * - The volume lcn bitmap must be unlocked on entry and is unlocked | 806 | * - The volume lcn bitmap must be unlocked on entry and is unlocked |
| 809 | * on return. | 807 | * on return. |
| 810 | * - This function takes the volume lcn bitmap lock for writing and | 808 | * - This function takes the volume lcn bitmap lock for writing and |
| 811 | * modifies the bitmap contents. | 809 | * modifies the bitmap contents. |
| 812 | */ | 810 | */ |
| 813 | s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | 811 | s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, |
| 814 | const BOOL write_locked, const BOOL is_rollback) | 812 | const BOOL is_rollback) |
| 815 | { | 813 | { |
| 816 | s64 delta, to_free, total_freed, real_freed; | 814 | s64 delta, to_free, total_freed, real_freed; |
| 817 | ntfs_inode *ni; | ||
| 818 | ntfs_volume *vol; | 815 | ntfs_volume *vol; |
| 819 | struct inode *lcnbmp_vi; | 816 | struct inode *lcnbmp_vi; |
| 820 | runlist_element *rl; | 817 | runlist_element *rl; |
| 821 | int err; | 818 | int err; |
| 822 | 819 | ||
| 823 | BUG_ON(!vi); | 820 | BUG_ON(!ni); |
| 824 | ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count " | 821 | ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count " |
| 825 | "0x%llx.%s", vi->i_ino, (unsigned long long)start_vcn, | 822 | "0x%llx.%s", ni->mft_no, (unsigned long long)start_vcn, |
| 826 | (unsigned long long)count, | 823 | (unsigned long long)count, |
| 827 | is_rollback ? " (rollback)" : ""); | 824 | is_rollback ? " (rollback)" : ""); |
| 828 | ni = NTFS_I(vi); | ||
| 829 | vol = ni->vol; | 825 | vol = ni->vol; |
| 830 | lcnbmp_vi = vol->lcnbmp_ino; | 826 | lcnbmp_vi = vol->lcnbmp_ino; |
| 831 | BUG_ON(!lcnbmp_vi); | 827 | BUG_ON(!lcnbmp_vi); |
| @@ -843,7 +839,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count, | |||
| 843 | 839 | ||
| 844 | total_freed = real_freed = 0; | 840 | total_freed = real_freed = 0; |
| 845 | 841 | ||
| 846 | rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, write_locked); | 842 | rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, TRUE); |
| 847 | if (IS_ERR(rl)) { | 843 | if (IS_ERR(rl)) { |
| 848 | if (!is_rollback) | 844 | if (!is_rollback) |
| 849 | ntfs_error(vol->sb, "Failed to find first runlist " | 845 | 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, | |||
| 897 | 893 | ||
| 898 | /* Attempt to map runlist. */ | 894 | /* Attempt to map runlist. */ |
| 899 | vcn = rl->vcn; | 895 | vcn = rl->vcn; |
| 900 | rl = ntfs_attr_find_vcn_nolock(ni, vcn, write_locked); | 896 | rl = ntfs_attr_find_vcn_nolock(ni, vcn, TRUE); |
| 901 | if (IS_ERR(rl)) { | 897 | if (IS_ERR(rl)) { |
| 902 | err = PTR_ERR(rl); | 898 | err = PTR_ERR(rl); |
| 903 | if (!is_rollback) | 899 | if (!is_rollback) |
| @@ -965,8 +961,7 @@ err_out: | |||
| 965 | * If rollback fails, set the volume errors flag, emit an error | 961 | * If rollback fails, set the volume errors flag, emit an error |
| 966 | * message, and return the error code. | 962 | * message, and return the error code. |
| 967 | */ | 963 | */ |
| 968 | delta = __ntfs_cluster_free(vi, start_vcn, total_freed, write_locked, | 964 | delta = __ntfs_cluster_free(ni, start_vcn, total_freed, TRUE); |
| 969 | TRUE); | ||
| 970 | if (delta < 0) { | 965 | if (delta < 0) { |
| 971 | ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " | 966 | ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " |
| 972 | "inconsistent metadata! Unmount and run " | 967 | "inconsistent metadata! Unmount and run " |
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h index e4d7fb98d685..a6a8827882e7 100644 --- a/fs/ntfs/lcnalloc.h +++ b/fs/ntfs/lcnalloc.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * lcnalloc.h - Exports for NTFS kernel cluster (de)allocation. Part of the | 2 | * lcnalloc.h - Exports for NTFS kernel cluster (de)allocation. Part of the |
| 3 | * Linux-NTFS project. | 3 | * Linux-NTFS project. |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2004 Anton Altaparmakov | 5 | * Copyright (c) 2004-2005 Anton Altaparmakov |
| 6 | * | 6 | * |
| 7 | * This program/include file is free software; you can redistribute it and/or | 7 | * This program/include file is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License as published | 8 | * modify it under the terms of the GNU General Public License as published |
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
| 29 | 29 | ||
| 30 | #include "types.h" | 30 | #include "types.h" |
| 31 | #include "inode.h" | ||
| 31 | #include "runlist.h" | 32 | #include "runlist.h" |
| 32 | #include "volume.h" | 33 | #include "volume.h" |
| 33 | 34 | ||
| @@ -42,18 +43,17 @@ extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, | |||
| 42 | const VCN start_vcn, const s64 count, const LCN start_lcn, | 43 | const VCN start_vcn, const s64 count, const LCN start_lcn, |
| 43 | const NTFS_CLUSTER_ALLOCATION_ZONES zone); | 44 | const NTFS_CLUSTER_ALLOCATION_ZONES zone); |
| 44 | 45 | ||
| 45 | extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, | 46 | extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, |
| 46 | s64 count, const BOOL write_locked, const BOOL is_rollback); | 47 | s64 count, const BOOL is_rollback); |
| 47 | 48 | ||
| 48 | /** | 49 | /** |
| 49 | * ntfs_cluster_free - free clusters on an ntfs volume | 50 | * ntfs_cluster_free - free clusters on an ntfs volume |
| 50 | * @vi: vfs inode whose runlist describes the clusters to free | 51 | * @ni: ntfs inode whose runlist describes the clusters to free |
| 51 | * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters | 52 | * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters |
| 52 | * @count: number of clusters to free or -1 for all clusters | 53 | * @count: number of clusters to free or -1 for all clusters |
| 53 | * @write_locked: true if the runlist is locked for writing | ||
| 54 | * | 54 | * |
| 55 | * Free @count clusters starting at the cluster @start_vcn in the runlist | 55 | * Free @count clusters starting at the cluster @start_vcn in the runlist |
| 56 | * described by the vfs inode @vi. | 56 | * described by the ntfs inode @ni. |
| 57 | * | 57 | * |
| 58 | * If @count is -1, all clusters from @start_vcn to the end of the runlist are | 58 | * If @count is -1, all clusters from @start_vcn to the end of the runlist are |
| 59 | * deallocated. Thus, to completely free all clusters in a runlist, use | 59 | * 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, | |||
| 65 | * Return the number of deallocated clusters (not counting sparse ones) on | 65 | * Return the number of deallocated clusters (not counting sparse ones) on |
| 66 | * success and -errno on error. | 66 | * success and -errno on error. |
| 67 | * | 67 | * |
| 68 | * Locking: - The runlist described by @vi must be locked on entry and is | 68 | * Locking: - The runlist described by @ni must be locked for writing on entry |
| 69 | * locked on return. Note if the runlist is locked for reading the | 69 | * and is locked on return. Note the runlist may be modified when |
| 70 | * lock may be dropped and reacquired. Note the runlist may be | 70 | * needed runlist fragments need to be mapped. |
| 71 | * modified when needed runlist fragments need to be mapped. | ||
| 72 | * - The volume lcn bitmap must be unlocked on entry and is unlocked | 71 | * - The volume lcn bitmap must be unlocked on entry and is unlocked |
| 73 | * on return. | 72 | * on return. |
| 74 | * - This function takes the volume lcn bitmap lock for writing and | 73 | * - This function takes the volume lcn bitmap lock for writing and |
| 75 | * modifies the bitmap contents. | 74 | * modifies the bitmap contents. |
| 76 | */ | 75 | */ |
| 77 | static inline s64 ntfs_cluster_free(struct inode *vi, const VCN start_vcn, | 76 | static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, |
| 78 | s64 count, const BOOL write_locked) | 77 | s64 count) |
| 79 | { | 78 | { |
| 80 | return __ntfs_cluster_free(vi, start_vcn, count, write_locked, FALSE); | 79 | return __ntfs_cluster_free(ni, start_vcn, count, FALSE); |
| 81 | } | 80 | } |
| 82 | 81 | ||
| 83 | extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, | 82 | extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, |
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index 0173e95500d9..0fd70295cca6 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, | |||
| 51 | RESTART_PAGE_HEADER *rp, s64 pos) | 51 | RESTART_PAGE_HEADER *rp, s64 pos) |
| 52 | { | 52 | { |
| 53 | u32 logfile_system_page_size, logfile_log_page_size; | 53 | u32 logfile_system_page_size, logfile_log_page_size; |
| 54 | u16 usa_count, usa_ofs, usa_end, ra_ofs; | 54 | u16 ra_ofs, usa_count, usa_ofs, usa_end = 0; |
| 55 | BOOL have_usa = TRUE; | ||
| 55 | 56 | ||
| 56 | ntfs_debug("Entering."); | 57 | ntfs_debug("Entering."); |
| 57 | /* | 58 | /* |
| @@ -86,6 +87,14 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi, | |||
| 86 | (int)sle16_to_cpu(rp->minor_ver)); | 87 | (int)sle16_to_cpu(rp->minor_ver)); |
| 87 | return FALSE; | 88 | return FALSE; |
| 88 | } | 89 | } |
| 90 | /* | ||
| 91 | * If chkdsk has been run the restart page may not be protected by an | ||
| 92 | * update sequence array. | ||
| 93 | */ | ||
| 94 | if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) { | ||
| 95 | have_usa = FALSE; | ||
| 96 | goto skip_usa_checks; | ||
| 97 | } | ||
| 89 | /* Verify the size of the update sequence array. */ | 98 | /* Verify the size of the update sequence array. */ |
| 90 | usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS); | 99 | usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS); |
| 91 | if (usa_count != le16_to_cpu(rp->usa_count)) { | 100 | if (usa_count != le16_to_cpu(rp->usa_count)) { |
| @@ -102,6 +111,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi, | |||
| 102 | "inconsistent update sequence array offset."); | 111 | "inconsistent update sequence array offset."); |
| 103 | return FALSE; | 112 | return FALSE; |
| 104 | } | 113 | } |
| 114 | skip_usa_checks: | ||
| 105 | /* | 115 | /* |
| 106 | * Verify the position of the restart area. It must be: | 116 | * Verify the position of the restart area. It must be: |
| 107 | * - aligned to 8-byte boundary, | 117 | * - aligned to 8-byte boundary, |
| @@ -109,7 +119,8 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi, | |||
| 109 | * - within the system page size. | 119 | * - within the system page size. |
| 110 | */ | 120 | */ |
| 111 | ra_ofs = le16_to_cpu(rp->restart_area_offset); | 121 | ra_ofs = le16_to_cpu(rp->restart_area_offset); |
| 112 | if (ra_ofs & 7 || ra_ofs < usa_end || | 122 | if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end : |
| 123 | ra_ofs < sizeof(RESTART_PAGE_HEADER)) || | ||
| 113 | ra_ofs > logfile_system_page_size) { | 124 | ra_ofs > logfile_system_page_size) { |
| 114 | ntfs_error(vi->i_sb, "$LogFile restart page specifies " | 125 | ntfs_error(vi->i_sb, "$LogFile restart page specifies " |
| 115 | "inconsistent restart area offset."); | 126 | "inconsistent restart area offset."); |
| @@ -402,8 +413,12 @@ static int ntfs_check_and_load_restart_page(struct inode *vi, | |||
| 402 | idx++; | 413 | idx++; |
| 403 | } while (to_read > 0); | 414 | } while (to_read > 0); |
| 404 | } | 415 | } |
| 405 | /* Perform the multi sector transfer deprotection on the buffer. */ | 416 | /* |
| 406 | if (post_read_mst_fixup((NTFS_RECORD*)trp, | 417 | * Perform the multi sector transfer deprotection on the buffer if the |
| 418 | * restart page is protected. | ||
| 419 | */ | ||
| 420 | if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count)) | ||
| 421 | && post_read_mst_fixup((NTFS_RECORD*)trp, | ||
| 407 | le32_to_cpu(rp->system_page_size))) { | 422 | le32_to_cpu(rp->system_page_size))) { |
| 408 | /* | 423 | /* |
| 409 | * A multi sector tranfer error was detected. We only need to | 424 | * A multi sector tranfer error was detected. We only need to |
| @@ -615,11 +630,16 @@ is_empty: | |||
| 615 | * Otherwise just throw it away. | 630 | * Otherwise just throw it away. |
| 616 | */ | 631 | */ |
| 617 | if (rstr2_lsn > rstr1_lsn) { | 632 | if (rstr2_lsn > rstr1_lsn) { |
| 633 | ntfs_debug("Using second restart page as it is more " | ||
| 634 | "recent."); | ||
| 618 | ntfs_free(rstr1_ph); | 635 | ntfs_free(rstr1_ph); |
| 619 | rstr1_ph = rstr2_ph; | 636 | rstr1_ph = rstr2_ph; |
| 620 | /* rstr1_lsn = rstr2_lsn; */ | 637 | /* rstr1_lsn = rstr2_lsn; */ |
| 621 | } else | 638 | } else { |
| 639 | ntfs_debug("Using first restart page as it is more " | ||
| 640 | "recent."); | ||
| 622 | ntfs_free(rstr2_ph); | 641 | ntfs_free(rstr2_ph); |
| 642 | } | ||
| 623 | rstr2_ph = NULL; | 643 | rstr2_ph = NULL; |
| 624 | } | 644 | } |
| 625 | /* All consistency checks passed. */ | 645 | /* All consistency checks passed. */ |
diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h index 42388f95ea6d..a51f3dd0e9eb 100644 --- a/fs/ntfs/logfile.h +++ b/fs/ntfs/logfile.h | |||
| @@ -113,7 +113,7 @@ typedef struct { | |||
| 113 | */ | 113 | */ |
| 114 | enum { | 114 | enum { |
| 115 | RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002), | 115 | RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002), |
| 116 | RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */ | 116 | RESTART_SPACE_FILLER = const_cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */ |
| 117 | } __attribute__ ((__packed__)); | 117 | } __attribute__ ((__packed__)); |
| 118 | 118 | ||
| 119 | typedef le16 RESTART_AREA_FLAGS; | 119 | typedef le16 RESTART_AREA_FLAGS; |
diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h index 3288bcc2c4aa..006946efca8c 100644 --- a/fs/ntfs/malloc.h +++ b/fs/ntfs/malloc.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * malloc.h - NTFS kernel memory handling. Part of the Linux-NTFS project. | 2 | * malloc.h - NTFS kernel memory handling. Part of the Linux-NTFS project. |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2001-2004 Anton Altaparmakov | 4 | * Copyright (c) 2001-2005 Anton Altaparmakov |
| 5 | * | 5 | * |
| 6 | * This program/include file is free software; you can redistribute it and/or | 6 | * This program/include file is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License as published | 7 | * modify it under the terms of the GNU General Public License as published |
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 2c32b84385a8..247586d1d5dc 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
| @@ -1953,7 +1953,7 @@ restore_undo_alloc: | |||
| 1953 | a = ctx->attr; | 1953 | a = ctx->attr; |
| 1954 | a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1); | 1954 | a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1); |
| 1955 | undo_alloc: | 1955 | undo_alloc: |
| 1956 | if (ntfs_cluster_free(vol->mft_ino, old_last_vcn, -1, TRUE) < 0) { | 1956 | if (ntfs_cluster_free(mft_ni, old_last_vcn, -1) < 0) { |
| 1957 | ntfs_error(vol->sb, "Failed to free clusters from mft data " | 1957 | ntfs_error(vol->sb, "Failed to free clusters from mft data " |
| 1958 | "attribute.%s", es); | 1958 | "attribute.%s", es); |
| 1959 | NVolSetErrors(vol); | 1959 | NVolSetErrors(vol); |
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index f5b2ac929081..061b5ff6b73c 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project. | 2 | * runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project. |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2001-2005 Anton Altaparmakov | 4 | * Copyright (c) 2001-2005 Anton Altaparmakov |
| 5 | * Copyright (c) 2002 Richard Russon | 5 | * Copyright (c) 2002-2005 Richard Russon |
| 6 | * | 6 | * |
| 7 | * This program/include file is free software; you can redistribute it and/or | 7 | * This program/include file is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License as published | 8 | * modify it under the terms of the GNU General Public License as published |
| @@ -158,17 +158,21 @@ static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst, | |||
| 158 | BUG_ON(!dst); | 158 | BUG_ON(!dst); |
| 159 | BUG_ON(!src); | 159 | BUG_ON(!src); |
| 160 | 160 | ||
| 161 | if ((dst->lcn < 0) || (src->lcn < 0)) { /* Are we merging holes? */ | 161 | /* We can merge unmapped regions even if they are misaligned. */ |
| 162 | if (dst->lcn == LCN_HOLE && src->lcn == LCN_HOLE) | 162 | if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED)) |
| 163 | return TRUE; | 163 | return TRUE; |
| 164 | /* If the runs are misaligned, we cannot merge them. */ | ||
| 165 | if ((dst->vcn + dst->length) != src->vcn) | ||
| 164 | return FALSE; | 166 | return FALSE; |
| 165 | } | 167 | /* If both runs are non-sparse and contiguous, we can merge them. */ |
| 166 | if ((dst->lcn + dst->length) != src->lcn) /* Are the runs contiguous? */ | 168 | if ((dst->lcn >= 0) && (src->lcn >= 0) && |
| 167 | return FALSE; | 169 | ((dst->lcn + dst->length) == src->lcn)) |
| 168 | if ((dst->vcn + dst->length) != src->vcn) /* Are the runs misaligned? */ | 170 | return TRUE; |
| 169 | return FALSE; | 171 | /* If we are merging two holes, we can merge them. */ |
| 170 | 172 | if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE)) | |
| 171 | return TRUE; | 173 | return TRUE; |
| 174 | /* Cannot merge. */ | ||
| 175 | return FALSE; | ||
| 172 | } | 176 | } |
| 173 | 177 | ||
| 174 | /** | 178 | /** |
| @@ -214,14 +218,15 @@ static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src) | |||
| 214 | static inline runlist_element *ntfs_rl_append(runlist_element *dst, | 218 | static inline runlist_element *ntfs_rl_append(runlist_element *dst, |
| 215 | int dsize, runlist_element *src, int ssize, int loc) | 219 | int dsize, runlist_element *src, int ssize, int loc) |
| 216 | { | 220 | { |
| 217 | BOOL right; | 221 | BOOL right = FALSE; /* Right end of @src needs merging. */ |
| 218 | int magic; | 222 | int marker; /* End of the inserted runs. */ |
| 219 | 223 | ||
| 220 | BUG_ON(!dst); | 224 | BUG_ON(!dst); |
| 221 | BUG_ON(!src); | 225 | BUG_ON(!src); |
| 222 | 226 | ||
| 223 | /* First, check if the right hand end needs merging. */ | 227 | /* First, check if the right hand end needs merging. */ |
| 224 | right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); | 228 | if ((loc + 1) < dsize) |
| 229 | right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); | ||
| 225 | 230 | ||
| 226 | /* Space required: @dst size + @src size, less one if we merged. */ | 231 | /* Space required: @dst size + @src size, less one if we merged. */ |
| 227 | dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right); | 232 | dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right); |
| @@ -236,18 +241,19 @@ static inline runlist_element *ntfs_rl_append(runlist_element *dst, | |||
| 236 | if (right) | 241 | if (right) |
| 237 | __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); | 242 | __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); |
| 238 | 243 | ||
| 239 | magic = loc + ssize; | 244 | /* First run after the @src runs that have been inserted. */ |
| 245 | marker = loc + ssize + 1; | ||
| 240 | 246 | ||
| 241 | /* Move the tail of @dst out of the way, then copy in @src. */ | 247 | /* Move the tail of @dst out of the way, then copy in @src. */ |
| 242 | ntfs_rl_mm(dst, magic + 1, loc + 1 + right, dsize - loc - 1 - right); | 248 | ntfs_rl_mm(dst, marker, loc + 1 + right, dsize - (loc + 1 + right)); |
| 243 | ntfs_rl_mc(dst, loc + 1, src, 0, ssize); | 249 | ntfs_rl_mc(dst, loc + 1, src, 0, ssize); |
| 244 | 250 | ||
| 245 | /* Adjust the size of the preceding hole. */ | 251 | /* Adjust the size of the preceding hole. */ |
| 246 | dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; | 252 | dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; |
| 247 | 253 | ||
| 248 | /* We may have changed the length of the file, so fix the end marker */ | 254 | /* We may have changed the length of the file, so fix the end marker */ |
| 249 | if (dst[magic + 1].lcn == LCN_ENOENT) | 255 | if (dst[marker].lcn == LCN_ENOENT) |
| 250 | dst[magic + 1].vcn = dst[magic].vcn + dst[magic].length; | 256 | dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; |
| 251 | 257 | ||
| 252 | return dst; | 258 | return dst; |
| 253 | } | 259 | } |
| @@ -279,18 +285,17 @@ static inline runlist_element *ntfs_rl_append(runlist_element *dst, | |||
| 279 | static inline runlist_element *ntfs_rl_insert(runlist_element *dst, | 285 | static inline runlist_element *ntfs_rl_insert(runlist_element *dst, |
| 280 | int dsize, runlist_element *src, int ssize, int loc) | 286 | int dsize, runlist_element *src, int ssize, int loc) |
| 281 | { | 287 | { |
| 282 | BOOL left = FALSE; | 288 | BOOL left = FALSE; /* Left end of @src needs merging. */ |
| 283 | BOOL disc = FALSE; /* Discontinuity */ | 289 | BOOL disc = FALSE; /* Discontinuity between @dst and @src. */ |
| 284 | BOOL hole = FALSE; /* Following a hole */ | 290 | int marker; /* End of the inserted runs. */ |
| 285 | int magic; | ||
| 286 | 291 | ||
| 287 | BUG_ON(!dst); | 292 | BUG_ON(!dst); |
| 288 | BUG_ON(!src); | 293 | BUG_ON(!src); |
| 289 | 294 | ||
| 290 | /* disc => Discontinuity between the end of @dst and the start of @src. | 295 | /* |
| 291 | * This means we might need to insert a hole. | 296 | * disc => Discontinuity between the end of @dst and the start of @src. |
| 292 | * hole => @dst ends with a hole or an unmapped region which we can | 297 | * This means we might need to insert a "not mapped" run. |
| 293 | * extend to match the discontinuity. */ | 298 | */ |
| 294 | if (loc == 0) | 299 | if (loc == 0) |
| 295 | disc = (src[0].vcn > 0); | 300 | disc = (src[0].vcn > 0); |
| 296 | else { | 301 | else { |
| @@ -303,58 +308,49 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst, | |||
| 303 | merged_length += src->length; | 308 | merged_length += src->length; |
| 304 | 309 | ||
| 305 | disc = (src[0].vcn > dst[loc - 1].vcn + merged_length); | 310 | disc = (src[0].vcn > dst[loc - 1].vcn + merged_length); |
| 306 | if (disc) | ||
| 307 | hole = (dst[loc - 1].lcn == LCN_HOLE); | ||
| 308 | } | 311 | } |
| 309 | 312 | /* | |
| 310 | /* Space required: @dst size + @src size, less one if we merged, plus | 313 | * Space required: @dst size + @src size, less one if we merged, plus |
| 311 | * one if there was a discontinuity, less one for a trailing hole. */ | 314 | * one if there was a discontinuity. |
| 312 | dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc - hole); | 315 | */ |
| 316 | dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc); | ||
| 313 | if (IS_ERR(dst)) | 317 | if (IS_ERR(dst)) |
| 314 | return dst; | 318 | return dst; |
| 315 | /* | 319 | /* |
| 316 | * We are guaranteed to succeed from here so can start modifying the | 320 | * We are guaranteed to succeed from here so can start modifying the |
| 317 | * original runlist. | 321 | * original runlist. |
| 318 | */ | 322 | */ |
| 319 | |||
| 320 | if (left) | 323 | if (left) |
| 321 | __ntfs_rl_merge(dst + loc - 1, src); | 324 | __ntfs_rl_merge(dst + loc - 1, src); |
| 322 | 325 | /* | |
| 323 | magic = loc + ssize - left + disc - hole; | 326 | * First run after the @src runs that have been inserted. |
| 327 | * Nominally, @marker equals @loc + @ssize, i.e. location + number of | ||
| 328 | * runs in @src. However, if @left, then the first run in @src has | ||
| 329 | * been merged with one in @dst. And if @disc, then @dst and @src do | ||
| 330 | * not meet and we need an extra run to fill the gap. | ||
| 331 | */ | ||
| 332 | marker = loc + ssize - left + disc; | ||
| 324 | 333 | ||
| 325 | /* Move the tail of @dst out of the way, then copy in @src. */ | 334 | /* Move the tail of @dst out of the way, then copy in @src. */ |
| 326 | ntfs_rl_mm(dst, magic, loc, dsize - loc); | 335 | ntfs_rl_mm(dst, marker, loc, dsize - loc); |
| 327 | ntfs_rl_mc(dst, loc + disc - hole, src, left, ssize - left); | 336 | ntfs_rl_mc(dst, loc + disc, src, left, ssize - left); |
| 328 | 337 | ||
| 329 | /* Adjust the VCN of the last run ... */ | 338 | /* Adjust the VCN of the first run after the insertion... */ |
| 330 | if (dst[magic].lcn <= LCN_HOLE) | 339 | dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; |
| 331 | dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length; | ||
| 332 | /* ... and the length. */ | 340 | /* ... and the length. */ |
| 333 | if (dst[magic].lcn == LCN_HOLE || dst[magic].lcn == LCN_RL_NOT_MAPPED) | 341 | if (dst[marker].lcn == LCN_HOLE || dst[marker].lcn == LCN_RL_NOT_MAPPED) |
| 334 | dst[magic].length = dst[magic + 1].vcn - dst[magic].vcn; | 342 | dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn; |
| 335 | 343 | ||
| 336 | /* Writing beyond the end of the file and there's a discontinuity. */ | 344 | /* Writing beyond the end of the file and there is a discontinuity. */ |
| 337 | if (disc) { | 345 | if (disc) { |
| 338 | if (hole) | 346 | if (loc > 0) { |
| 339 | dst[loc - 1].length = dst[loc].vcn - dst[loc - 1].vcn; | 347 | dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length; |
| 340 | else { | 348 | dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; |
| 341 | if (loc > 0) { | 349 | } else { |
| 342 | dst[loc].vcn = dst[loc - 1].vcn + | 350 | dst[loc].vcn = 0; |
| 343 | dst[loc - 1].length; | 351 | dst[loc].length = dst[loc + 1].vcn; |
| 344 | dst[loc].length = dst[loc + 1].vcn - | ||
| 345 | dst[loc].vcn; | ||
| 346 | } else { | ||
| 347 | dst[loc].vcn = 0; | ||
| 348 | dst[loc].length = dst[loc + 1].vcn; | ||
| 349 | } | ||
| 350 | dst[loc].lcn = LCN_RL_NOT_MAPPED; | ||
| 351 | } | 352 | } |
| 352 | 353 | dst[loc].lcn = LCN_RL_NOT_MAPPED; | |
| 353 | magic += hole; | ||
| 354 | |||
| 355 | if (dst[magic].lcn == LCN_ENOENT) | ||
| 356 | dst[magic].vcn = dst[magic - 1].vcn + | ||
| 357 | dst[magic - 1].length; | ||
| 358 | } | 354 | } |
| 359 | return dst; | 355 | return dst; |
| 360 | } | 356 | } |
| @@ -385,20 +381,23 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst, | |||
| 385 | static inline runlist_element *ntfs_rl_replace(runlist_element *dst, | 381 | static inline runlist_element *ntfs_rl_replace(runlist_element *dst, |
| 386 | int dsize, runlist_element *src, int ssize, int loc) | 382 | int dsize, runlist_element *src, int ssize, int loc) |
| 387 | { | 383 | { |
| 388 | BOOL left = FALSE; | 384 | BOOL left = FALSE; /* Left end of @src needs merging. */ |
| 389 | BOOL right; | 385 | BOOL right = FALSE; /* Right end of @src needs merging. */ |
| 390 | int magic; | 386 | int tail; /* Start of tail of @dst. */ |
| 387 | int marker; /* End of the inserted runs. */ | ||
| 391 | 388 | ||
| 392 | BUG_ON(!dst); | 389 | BUG_ON(!dst); |
| 393 | BUG_ON(!src); | 390 | BUG_ON(!src); |
| 394 | 391 | ||
| 395 | /* First, merge the left and right ends, if necessary. */ | 392 | /* First, see if the left and right ends need merging. */ |
| 396 | right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); | 393 | if ((loc + 1) < dsize) |
| 394 | right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); | ||
| 397 | if (loc > 0) | 395 | if (loc > 0) |
| 398 | left = ntfs_are_rl_mergeable(dst + loc - 1, src); | 396 | left = ntfs_are_rl_mergeable(dst + loc - 1, src); |
| 399 | 397 | /* | |
| 400 | /* Allocate some space. We'll need less if the left, right, or both | 398 | * Allocate some space. We will need less if the left, right, or both |
| 401 | * ends were merged. */ | 399 | * ends get merged. |
| 400 | */ | ||
| 402 | dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right); | 401 | dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right); |
| 403 | if (IS_ERR(dst)) | 402 | if (IS_ERR(dst)) |
| 404 | return dst; | 403 | return dst; |
| @@ -406,21 +405,37 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst, | |||
| 406 | * We are guaranteed to succeed from here so can start modifying the | 405 | * We are guaranteed to succeed from here so can start modifying the |
| 407 | * original runlists. | 406 | * original runlists. |
| 408 | */ | 407 | */ |
| 408 | |||
| 409 | /* First, merge the left and right ends, if necessary. */ | ||
| 409 | if (right) | 410 | if (right) |
| 410 | __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); | 411 | __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); |
| 411 | if (left) | 412 | if (left) |
| 412 | __ntfs_rl_merge(dst + loc - 1, src); | 413 | __ntfs_rl_merge(dst + loc - 1, src); |
| 413 | 414 | /* | |
| 414 | /* FIXME: What does this mean? (AIA) */ | 415 | * Offset of the tail of @dst. This needs to be moved out of the way |
| 415 | magic = loc + ssize - left; | 416 | * to make space for the runs to be copied from @src, i.e. the first |
| 417 | * run of the tail of @dst. | ||
| 418 | * Nominally, @tail equals @loc + 1, i.e. location, skipping the | ||
| 419 | * replaced run. However, if @right, then one of @dst's runs is | ||
| 420 | * already merged into @src. | ||
| 421 | */ | ||
| 422 | tail = loc + right + 1; | ||
| 423 | /* | ||
| 424 | * First run after the @src runs that have been inserted, i.e. where | ||
| 425 | * the tail of @dst needs to be moved to. | ||
| 426 | * Nominally, @marker equals @loc + @ssize, i.e. location + number of | ||
| 427 | * runs in @src. However, if @left, then the first run in @src has | ||
| 428 | * been merged with one in @dst. | ||
| 429 | */ | ||
| 430 | marker = loc + ssize - left; | ||
| 416 | 431 | ||
| 417 | /* Move the tail of @dst out of the way, then copy in @src. */ | 432 | /* Move the tail of @dst out of the way, then copy in @src. */ |
| 418 | ntfs_rl_mm(dst, magic, loc + right + 1, dsize - loc - right - 1); | 433 | ntfs_rl_mm(dst, marker, tail, dsize - tail); |
| 419 | ntfs_rl_mc(dst, loc, src, left, ssize - left); | 434 | ntfs_rl_mc(dst, loc, src, left, ssize - left); |
| 420 | 435 | ||
| 421 | /* We may have changed the length of the file, so fix the end marker */ | 436 | /* We may have changed the length of the file, so fix the end marker. */ |
| 422 | if (dst[magic].lcn == LCN_ENOENT) | 437 | if (dsize - tail > 0 && dst[marker].lcn == LCN_ENOENT) |
| 423 | dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length; | 438 | dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; |
| 424 | return dst; | 439 | return dst; |
| 425 | } | 440 | } |
| 426 | 441 | ||
| @@ -738,52 +738,15 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) | |||
| 738 | return error; | 738 | return error; |
| 739 | } | 739 | } |
| 740 | 740 | ||
| 741 | /* | 741 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, |
| 742 | * Note that while the flag value (low two bits) for sys_open means: | 742 | int flags, struct file *f) |
| 743 | * 00 - read-only | ||
| 744 | * 01 - write-only | ||
| 745 | * 10 - read-write | ||
| 746 | * 11 - special | ||
| 747 | * it is changed into | ||
| 748 | * 00 - no permissions needed | ||
| 749 | * 01 - read-permission | ||
| 750 | * 10 - write-permission | ||
| 751 | * 11 - read-write | ||
| 752 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | ||
| 753 | * used by symlinks. | ||
| 754 | */ | ||
| 755 | struct file *filp_open(const char * filename, int flags, int mode) | ||
| 756 | { | ||
| 757 | int namei_flags, error; | ||
| 758 | struct nameidata nd; | ||
| 759 | |||
| 760 | namei_flags = flags; | ||
| 761 | if ((namei_flags+1) & O_ACCMODE) | ||
| 762 | namei_flags++; | ||
| 763 | if (namei_flags & O_TRUNC) | ||
| 764 | namei_flags |= 2; | ||
| 765 | |||
| 766 | error = open_namei(filename, namei_flags, mode, &nd); | ||
| 767 | if (!error) | ||
| 768 | return dentry_open(nd.dentry, nd.mnt, flags); | ||
| 769 | |||
| 770 | return ERR_PTR(error); | ||
| 771 | } | ||
| 772 | |||
| 773 | EXPORT_SYMBOL(filp_open); | ||
| 774 | |||
| 775 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | ||
| 776 | { | 743 | { |
| 777 | struct file * f; | ||
| 778 | struct inode *inode; | 744 | struct inode *inode; |
| 779 | int error; | 745 | int error; |
| 780 | 746 | ||
| 781 | error = -ENFILE; | ||
| 782 | f = get_empty_filp(); | ||
| 783 | if (!f) | ||
| 784 | goto cleanup_dentry; | ||
| 785 | f->f_flags = flags; | 747 | f->f_flags = flags; |
| 786 | f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; | 748 | f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | |
| 749 | FMODE_PREAD | FMODE_PWRITE; | ||
| 787 | inode = dentry->d_inode; | 750 | inode = dentry->d_inode; |
| 788 | if (f->f_mode & FMODE_WRITE) { | 751 | if (f->f_mode & FMODE_WRITE) { |
| 789 | error = get_write_access(inode); | 752 | error = get_write_access(inode); |
| @@ -828,12 +791,63 @@ cleanup_all: | |||
| 828 | f->f_vfsmnt = NULL; | 791 | f->f_vfsmnt = NULL; |
| 829 | cleanup_file: | 792 | cleanup_file: |
| 830 | put_filp(f); | 793 | put_filp(f); |
| 831 | cleanup_dentry: | ||
| 832 | dput(dentry); | 794 | dput(dentry); |
| 833 | mntput(mnt); | 795 | mntput(mnt); |
| 834 | return ERR_PTR(error); | 796 | return ERR_PTR(error); |
| 835 | } | 797 | } |
| 836 | 798 | ||
| 799 | /* | ||
| 800 | * Note that while the flag value (low two bits) for sys_open means: | ||
| 801 | * 00 - read-only | ||
| 802 | * 01 - write-only | ||
| 803 | * 10 - read-write | ||
| 804 | * 11 - special | ||
| 805 | * it is changed into | ||
| 806 | * 00 - no permissions needed | ||
| 807 | * 01 - read-permission | ||
| 808 | * 10 - write-permission | ||
| 809 | * 11 - read-write | ||
| 810 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | ||
| 811 | * used by symlinks. | ||
| 812 | */ | ||
| 813 | struct file *filp_open(const char * filename, int flags, int mode) | ||
| 814 | { | ||
| 815 | int namei_flags, error; | ||
| 816 | struct nameidata nd; | ||
| 817 | struct file *f; | ||
| 818 | |||
| 819 | namei_flags = flags; | ||
| 820 | if ((namei_flags+1) & O_ACCMODE) | ||
| 821 | namei_flags++; | ||
| 822 | if (namei_flags & O_TRUNC) | ||
| 823 | namei_flags |= 2; | ||
| 824 | |||
| 825 | error = -ENFILE; | ||
| 826 | f = get_empty_filp(); | ||
| 827 | if (f == NULL) | ||
| 828 | return ERR_PTR(error); | ||
| 829 | |||
| 830 | error = open_namei(filename, namei_flags, mode, &nd); | ||
| 831 | if (!error) | ||
| 832 | return __dentry_open(nd.dentry, nd.mnt, flags, f); | ||
| 833 | |||
| 834 | put_filp(f); | ||
| 835 | return ERR_PTR(error); | ||
| 836 | } | ||
| 837 | EXPORT_SYMBOL(filp_open); | ||
| 838 | |||
| 839 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | ||
| 840 | { | ||
| 841 | int error; | ||
| 842 | struct file *f; | ||
| 843 | |||
| 844 | error = -ENFILE; | ||
| 845 | f = get_empty_filp(); | ||
| 846 | if (f == NULL) | ||
| 847 | return ERR_PTR(error); | ||
| 848 | |||
| 849 | return __dentry_open(dentry, mnt, flags, f); | ||
| 850 | } | ||
| 837 | EXPORT_SYMBOL(dentry_open); | 851 | EXPORT_SYMBOL(dentry_open); |
| 838 | 852 | ||
| 839 | /* | 853 | /* |
diff --git a/fs/proc/array.c b/fs/proc/array.c index d88d518d30f6..d84eecacbeaf 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -74,6 +74,7 @@ | |||
| 74 | #include <linux/file.h> | 74 | #include <linux/file.h> |
| 75 | #include <linux/times.h> | 75 | #include <linux/times.h> |
| 76 | #include <linux/cpuset.h> | 76 | #include <linux/cpuset.h> |
| 77 | #include <linux/rcupdate.h> | ||
| 77 | 78 | ||
| 78 | #include <asm/uaccess.h> | 79 | #include <asm/uaccess.h> |
| 79 | #include <asm/pgtable.h> | 80 | #include <asm/pgtable.h> |
| @@ -180,12 +181,14 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
| 180 | p->gid, p->egid, p->sgid, p->fsgid); | 181 | p->gid, p->egid, p->sgid, p->fsgid); |
| 181 | read_unlock(&tasklist_lock); | 182 | read_unlock(&tasklist_lock); |
| 182 | task_lock(p); | 183 | task_lock(p); |
| 184 | rcu_read_lock(); | ||
| 183 | if (p->files) | 185 | if (p->files) |
| 184 | fdt = files_fdtable(p->files); | 186 | fdt = files_fdtable(p->files); |
| 185 | buffer += sprintf(buffer, | 187 | buffer += sprintf(buffer, |
| 186 | "FDSize:\t%d\n" | 188 | "FDSize:\t%d\n" |
| 187 | "Groups:\t", | 189 | "Groups:\t", |
| 188 | fdt ? fdt->max_fds : 0); | 190 | fdt ? fdt->max_fds : 0); |
| 191 | rcu_read_unlock(); | ||
| 189 | 192 | ||
| 190 | group_info = p->group_info; | 193 | group_info = p->group_info; |
| 191 | get_group_info(group_info); | 194 | get_group_info(group_info); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 23db452ab428..3b33f94020db 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -340,6 +340,54 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf | |||
| 340 | return result; | 340 | return result; |
| 341 | } | 341 | } |
| 342 | 342 | ||
| 343 | |||
| 344 | /* Same as proc_root_link, but this addionally tries to get fs from other | ||
| 345 | * threads in the group */ | ||
| 346 | static int proc_task_root_link(struct inode *inode, struct dentry **dentry, | ||
| 347 | struct vfsmount **mnt) | ||
| 348 | { | ||
| 349 | struct fs_struct *fs; | ||
| 350 | int result = -ENOENT; | ||
| 351 | struct task_struct *leader = proc_task(inode); | ||
| 352 | |||
| 353 | task_lock(leader); | ||
| 354 | fs = leader->fs; | ||
| 355 | if (fs) { | ||
| 356 | atomic_inc(&fs->count); | ||
| 357 | task_unlock(leader); | ||
| 358 | } else { | ||
| 359 | /* Try to get fs from other threads */ | ||
| 360 | task_unlock(leader); | ||
| 361 | read_lock(&tasklist_lock); | ||
| 362 | if (pid_alive(leader)) { | ||
| 363 | struct task_struct *task = leader; | ||
| 364 | |||
| 365 | while ((task = next_thread(task)) != leader) { | ||
| 366 | task_lock(task); | ||
| 367 | fs = task->fs; | ||
| 368 | if (fs) { | ||
| 369 | atomic_inc(&fs->count); | ||
| 370 | task_unlock(task); | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | task_unlock(task); | ||
| 374 | } | ||
| 375 | } | ||
| 376 | read_unlock(&tasklist_lock); | ||
| 377 | } | ||
| 378 | |||
| 379 | if (fs) { | ||
| 380 | read_lock(&fs->lock); | ||
| 381 | *mnt = mntget(fs->rootmnt); | ||
| 382 | *dentry = dget(fs->root); | ||
| 383 | read_unlock(&fs->lock); | ||
| 384 | result = 0; | ||
| 385 | put_fs_struct(fs); | ||
| 386 | } | ||
| 387 | return result; | ||
| 388 | } | ||
| 389 | |||
| 390 | |||
| 343 | #define MAY_PTRACE(task) \ | 391 | #define MAY_PTRACE(task) \ |
| 344 | (task == current || \ | 392 | (task == current || \ |
| 345 | (task->parent == current && \ | 393 | (task->parent == current && \ |
| @@ -471,14 +519,14 @@ static int proc_oom_score(struct task_struct *task, char *buffer) | |||
| 471 | 519 | ||
| 472 | /* permission checks */ | 520 | /* permission checks */ |
| 473 | 521 | ||
| 474 | static int proc_check_root(struct inode *inode) | 522 | /* If the process being read is separated by chroot from the reading process, |
| 523 | * don't let the reader access the threads. | ||
| 524 | */ | ||
| 525 | static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) | ||
| 475 | { | 526 | { |
| 476 | struct dentry *de, *base, *root; | 527 | struct dentry *de, *base; |
| 477 | struct vfsmount *our_vfsmnt, *vfsmnt, *mnt; | 528 | struct vfsmount *our_vfsmnt, *mnt; |
| 478 | int res = 0; | 529 | int res = 0; |
| 479 | |||
| 480 | if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */ | ||
| 481 | return -ENOENT; | ||
| 482 | read_lock(¤t->fs->lock); | 530 | read_lock(¤t->fs->lock); |
| 483 | our_vfsmnt = mntget(current->fs->rootmnt); | 531 | our_vfsmnt = mntget(current->fs->rootmnt); |
| 484 | base = dget(current->fs->root); | 532 | base = dget(current->fs->root); |
| @@ -511,6 +559,16 @@ out: | |||
| 511 | goto exit; | 559 | goto exit; |
| 512 | } | 560 | } |
| 513 | 561 | ||
| 562 | static int proc_check_root(struct inode *inode) | ||
| 563 | { | ||
| 564 | struct dentry *root; | ||
| 565 | struct vfsmount *vfsmnt; | ||
| 566 | |||
| 567 | if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */ | ||
| 568 | return -ENOENT; | ||
| 569 | return proc_check_chroot(root, vfsmnt); | ||
| 570 | } | ||
| 571 | |||
| 514 | static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) | 572 | static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) |
| 515 | { | 573 | { |
| 516 | if (generic_permission(inode, mask, NULL) != 0) | 574 | if (generic_permission(inode, mask, NULL) != 0) |
| @@ -518,6 +576,20 @@ static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 518 | return proc_check_root(inode); | 576 | return proc_check_root(inode); |
| 519 | } | 577 | } |
| 520 | 578 | ||
| 579 | static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd) | ||
| 580 | { | ||
| 581 | struct dentry *root; | ||
| 582 | struct vfsmount *vfsmnt; | ||
| 583 | |||
| 584 | if (generic_permission(inode, mask, NULL) != 0) | ||
| 585 | return -EACCES; | ||
| 586 | |||
| 587 | if (proc_task_root_link(inode, &root, &vfsmnt)) | ||
| 588 | return -ENOENT; | ||
| 589 | |||
| 590 | return proc_check_chroot(root, vfsmnt); | ||
| 591 | } | ||
| 592 | |||
| 521 | extern struct seq_operations proc_pid_maps_op; | 593 | extern struct seq_operations proc_pid_maps_op; |
| 522 | static int maps_open(struct inode *inode, struct file *file) | 594 | static int maps_open(struct inode *inode, struct file *file) |
| 523 | { | 595 | { |
| @@ -1419,7 +1491,7 @@ static struct inode_operations proc_fd_inode_operations = { | |||
| 1419 | 1491 | ||
| 1420 | static struct inode_operations proc_task_inode_operations = { | 1492 | static struct inode_operations proc_task_inode_operations = { |
| 1421 | .lookup = proc_task_lookup, | 1493 | .lookup = proc_task_lookup, |
| 1422 | .permission = proc_permission, | 1494 | .permission = proc_task_permission, |
| 1423 | }; | 1495 | }; |
| 1424 | 1496 | ||
| 1425 | #ifdef CONFIG_SECURITY | 1497 | #ifdef CONFIG_SECURITY |
diff --git a/fs/read_write.c b/fs/read_write.c index b60324aaa2b6..a091ee4f430d 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, | |||
| 499 | ret = rw_verify_area(type, file, pos, tot_len); | 499 | ret = rw_verify_area(type, file, pos, tot_len); |
| 500 | if (ret) | 500 | if (ret) |
| 501 | goto out; | 501 | goto out; |
| 502 | ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE); | ||
| 503 | if (ret) | ||
| 504 | goto out; | ||
| 502 | 505 | ||
| 503 | fnv = NULL; | 506 | fnv = NULL; |
| 504 | if (type == READ) { | 507 | if (type == READ) { |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index c9f178fb494f..c20babd6216d 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
| @@ -667,7 +667,7 @@ static int reiserfs_allocate_blocks_for_region(struct reiserfs_transaction_handl | |||
| 667 | if (th->t_trans_id) { | 667 | if (th->t_trans_id) { |
| 668 | int err; | 668 | int err; |
| 669 | // update any changes we made to blk count | 669 | // update any changes we made to blk count |
| 670 | reiserfs_update_sd(th, inode); | 670 | mark_inode_dirty(inode); |
| 671 | err = | 671 | err = |
| 672 | journal_end(th, inode->i_sb, | 672 | journal_end(th, inode->i_sb, |
| 673 | JOURNAL_PER_BALANCE_CNT * 3 + 1 + | 673 | JOURNAL_PER_BALANCE_CNT * 3 + 1 + |
| @@ -855,17 +855,18 @@ static int reiserfs_submit_file_region_for_write(struct reiserfs_transaction_han | |||
| 855 | 855 | ||
| 856 | if (th->t_trans_id) { | 856 | if (th->t_trans_id) { |
| 857 | reiserfs_write_lock(inode->i_sb); | 857 | reiserfs_write_lock(inode->i_sb); |
| 858 | reiserfs_update_sd(th, inode); // And update on-disk metadata | 858 | // this sets the proper flags for O_SYNC to trigger a commit |
| 859 | mark_inode_dirty(inode); | ||
| 859 | reiserfs_write_unlock(inode->i_sb); | 860 | reiserfs_write_unlock(inode->i_sb); |
| 860 | } else | 861 | } else |
| 861 | inode->i_sb->s_op->dirty_inode(inode); | 862 | mark_inode_dirty(inode); |
| 862 | 863 | ||
| 863 | sd_update = 1; | 864 | sd_update = 1; |
| 864 | } | 865 | } |
| 865 | if (th->t_trans_id) { | 866 | if (th->t_trans_id) { |
| 866 | reiserfs_write_lock(inode->i_sb); | 867 | reiserfs_write_lock(inode->i_sb); |
| 867 | if (!sd_update) | 868 | if (!sd_update) |
| 868 | reiserfs_update_sd(th, inode); | 869 | mark_inode_dirty(inode); |
| 869 | status = journal_end(th, th->t_super, th->t_blocks_allocated); | 870 | status = journal_end(th, th->t_super, th->t_blocks_allocated); |
| 870 | if (status) | 871 | if (status) |
| 871 | retval = status; | 872 | retval = status; |
| @@ -1320,7 +1321,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t | |||
| 1320 | return err; | 1321 | return err; |
| 1321 | } | 1322 | } |
| 1322 | reiserfs_update_inode_transaction(inode); | 1323 | reiserfs_update_inode_transaction(inode); |
| 1323 | reiserfs_update_sd(&th, inode); | 1324 | mark_inode_dirty(inode); |
| 1324 | err = journal_end(&th, inode->i_sb, 1); | 1325 | err = journal_end(&th, inode->i_sb, 1); |
| 1325 | if (err) { | 1326 | if (err) { |
| 1326 | reiserfs_write_unlock(inode->i_sb); | 1327 | reiserfs_write_unlock(inode->i_sb); |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 1a8a1bf2154d..d76ee6c4f9b8 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
| @@ -2639,6 +2639,12 @@ static int reiserfs_commit_write(struct file *f, struct page *page, | |||
| 2639 | } | 2639 | } |
| 2640 | reiserfs_update_inode_transaction(inode); | 2640 | reiserfs_update_inode_transaction(inode); |
| 2641 | inode->i_size = pos; | 2641 | inode->i_size = pos; |
| 2642 | /* | ||
| 2643 | * this will just nest into our transaction. It's important | ||
| 2644 | * to use mark_inode_dirty so the inode gets pushed around on the | ||
| 2645 | * dirty lists, and so that O_SYNC works as expected | ||
| 2646 | */ | ||
| 2647 | mark_inode_dirty(inode); | ||
| 2642 | reiserfs_update_sd(&myth, inode); | 2648 | reiserfs_update_sd(&myth, inode); |
| 2643 | update_sd = 1; | 2649 | update_sd = 1; |
| 2644 | ret = journal_end(&myth, inode->i_sb, 1); | 2650 | ret = journal_end(&myth, inode->i_sb, 1); |
| @@ -2649,21 +2655,13 @@ static int reiserfs_commit_write(struct file *f, struct page *page, | |||
| 2649 | if (th) { | 2655 | if (th) { |
| 2650 | reiserfs_write_lock(inode->i_sb); | 2656 | reiserfs_write_lock(inode->i_sb); |
| 2651 | if (!update_sd) | 2657 | if (!update_sd) |
| 2652 | reiserfs_update_sd(th, inode); | 2658 | mark_inode_dirty(inode); |
| 2653 | ret = reiserfs_end_persistent_transaction(th); | 2659 | ret = reiserfs_end_persistent_transaction(th); |
| 2654 | reiserfs_write_unlock(inode->i_sb); | 2660 | reiserfs_write_unlock(inode->i_sb); |
| 2655 | if (ret) | 2661 | if (ret) |
| 2656 | goto out; | 2662 | goto out; |
| 2657 | } | 2663 | } |
| 2658 | 2664 | ||
| 2659 | /* we test for O_SYNC here so we can commit the transaction | ||
| 2660 | ** for any packed tails the file might have had | ||
| 2661 | */ | ||
| 2662 | if (f && (f->f_flags & O_SYNC)) { | ||
| 2663 | reiserfs_write_lock(inode->i_sb); | ||
| 2664 | ret = reiserfs_commit_for_inode(inode); | ||
| 2665 | reiserfs_write_unlock(inode->i_sb); | ||
| 2666 | } | ||
| 2667 | out: | 2665 | out: |
| 2668 | return ret; | 2666 | return ret; |
| 2669 | 2667 | ||
