diff options
Diffstat (limited to 'fs/hostfs/hostfs_kern.c')
-rw-r--r-- | fs/hostfs/hostfs_kern.c | 112 |
1 files changed, 62 insertions, 50 deletions
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index e021188ca110..b83a0343378b 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
@@ -24,6 +24,7 @@ struct hostfs_inode_info { | |||
24 | int fd; | 24 | int fd; |
25 | fmode_t mode; | 25 | fmode_t mode; |
26 | struct inode vfs_inode; | 26 | struct inode vfs_inode; |
27 | struct mutex open_mutex; | ||
27 | }; | 28 | }; |
28 | 29 | ||
29 | static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) | 30 | static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) |
@@ -92,16 +93,22 @@ static char *__dentry_name(struct dentry *dentry, char *name) | |||
92 | __putname(name); | 93 | __putname(name); |
93 | return NULL; | 94 | return NULL; |
94 | } | 95 | } |
96 | |||
97 | /* | ||
98 | * This function relies on the fact that dentry_path_raw() will place | ||
99 | * the path name at the end of the provided buffer. | ||
100 | */ | ||
101 | BUG_ON(p + strlen(p) + 1 != name + PATH_MAX); | ||
102 | |||
95 | strlcpy(name, root, PATH_MAX); | 103 | strlcpy(name, root, PATH_MAX); |
96 | if (len > p - name) { | 104 | if (len > p - name) { |
97 | __putname(name); | 105 | __putname(name); |
98 | return NULL; | 106 | return NULL; |
99 | } | 107 | } |
100 | if (p > name + len) { | 108 | |
101 | char *s = name + len; | 109 | if (p > name + len) |
102 | while ((*s++ = *p++) != '\0') | 110 | strcpy(name + len, p); |
103 | ; | 111 | |
104 | } | ||
105 | return name; | 112 | return name; |
106 | } | 113 | } |
107 | 114 | ||
@@ -135,21 +142,19 @@ static char *follow_link(char *link) | |||
135 | int len, n; | 142 | int len, n; |
136 | char *name, *resolved, *end; | 143 | char *name, *resolved, *end; |
137 | 144 | ||
138 | len = 64; | 145 | name = __getname(); |
139 | while (1) { | 146 | if (!name) { |
140 | n = -ENOMEM; | 147 | n = -ENOMEM; |
141 | name = kmalloc(len, GFP_KERNEL); | 148 | goto out_free; |
142 | if (name == NULL) | ||
143 | goto out; | ||
144 | |||
145 | n = hostfs_do_readlink(link, name, len); | ||
146 | if (n < len) | ||
147 | break; | ||
148 | len *= 2; | ||
149 | kfree(name); | ||
150 | } | 149 | } |
150 | |||
151 | n = hostfs_do_readlink(link, name, PATH_MAX); | ||
151 | if (n < 0) | 152 | if (n < 0) |
152 | goto out_free; | 153 | goto out_free; |
154 | else if (n == PATH_MAX) { | ||
155 | n = -E2BIG; | ||
156 | goto out_free; | ||
157 | } | ||
153 | 158 | ||
154 | if (*name == '/') | 159 | if (*name == '/') |
155 | return name; | 160 | return name; |
@@ -168,13 +173,12 @@ static char *follow_link(char *link) | |||
168 | } | 173 | } |
169 | 174 | ||
170 | sprintf(resolved, "%s%s", link, name); | 175 | sprintf(resolved, "%s%s", link, name); |
171 | kfree(name); | 176 | __putname(name); |
172 | kfree(link); | 177 | kfree(link); |
173 | return resolved; | 178 | return resolved; |
174 | 179 | ||
175 | out_free: | 180 | out_free: |
176 | kfree(name); | 181 | __putname(name); |
177 | out: | ||
178 | return ERR_PTR(n); | 182 | return ERR_PTR(n); |
179 | } | 183 | } |
180 | 184 | ||
@@ -225,6 +229,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb) | |||
225 | hi->fd = -1; | 229 | hi->fd = -1; |
226 | hi->mode = 0; | 230 | hi->mode = 0; |
227 | inode_init_once(&hi->vfs_inode); | 231 | inode_init_once(&hi->vfs_inode); |
232 | mutex_init(&hi->open_mutex); | ||
228 | return &hi->vfs_inode; | 233 | return &hi->vfs_inode; |
229 | } | 234 | } |
230 | 235 | ||
@@ -257,6 +262,9 @@ static int hostfs_show_options(struct seq_file *seq, struct dentry *root) | |||
257 | if (strlen(root_path) > offset) | 262 | if (strlen(root_path) > offset) |
258 | seq_printf(seq, ",%s", root_path + offset); | 263 | seq_printf(seq, ",%s", root_path + offset); |
259 | 264 | ||
265 | if (append) | ||
266 | seq_puts(seq, ",append"); | ||
267 | |||
260 | return 0; | 268 | return 0; |
261 | } | 269 | } |
262 | 270 | ||
@@ -284,6 +292,7 @@ static int hostfs_readdir(struct file *file, struct dir_context *ctx) | |||
284 | if (dir == NULL) | 292 | if (dir == NULL) |
285 | return -error; | 293 | return -error; |
286 | next = ctx->pos; | 294 | next = ctx->pos; |
295 | seek_dir(dir, next); | ||
287 | while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) { | 296 | while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) { |
288 | if (!dir_emit(ctx, name, len, ino, type)) | 297 | if (!dir_emit(ctx, name, len, ino, type)) |
289 | break; | 298 | break; |
@@ -293,13 +302,12 @@ static int hostfs_readdir(struct file *file, struct dir_context *ctx) | |||
293 | return 0; | 302 | return 0; |
294 | } | 303 | } |
295 | 304 | ||
296 | static int hostfs_file_open(struct inode *ino, struct file *file) | 305 | static int hostfs_open(struct inode *ino, struct file *file) |
297 | { | 306 | { |
298 | static DEFINE_MUTEX(open_mutex); | ||
299 | char *name; | 307 | char *name; |
300 | fmode_t mode = 0; | 308 | fmode_t mode; |
301 | int err; | 309 | int err; |
302 | int r = 0, w = 0, fd; | 310 | int r, w, fd; |
303 | 311 | ||
304 | mode = file->f_mode & (FMODE_READ | FMODE_WRITE); | 312 | mode = file->f_mode & (FMODE_READ | FMODE_WRITE); |
305 | if ((mode & HOSTFS_I(ino)->mode) == mode) | 313 | if ((mode & HOSTFS_I(ino)->mode) == mode) |
@@ -308,12 +316,12 @@ static int hostfs_file_open(struct inode *ino, struct file *file) | |||
308 | mode |= HOSTFS_I(ino)->mode; | 316 | mode |= HOSTFS_I(ino)->mode; |
309 | 317 | ||
310 | retry: | 318 | retry: |
319 | r = w = 0; | ||
320 | |||
311 | if (mode & FMODE_READ) | 321 | if (mode & FMODE_READ) |
312 | r = 1; | 322 | r = 1; |
313 | if (mode & FMODE_WRITE) | 323 | if (mode & FMODE_WRITE) |
314 | w = 1; | 324 | r = w = 1; |
315 | if (w) | ||
316 | r = 1; | ||
317 | 325 | ||
318 | name = dentry_name(file->f_path.dentry); | 326 | name = dentry_name(file->f_path.dentry); |
319 | if (name == NULL) | 327 | if (name == NULL) |
@@ -324,15 +332,16 @@ retry: | |||
324 | if (fd < 0) | 332 | if (fd < 0) |
325 | return fd; | 333 | return fd; |
326 | 334 | ||
327 | mutex_lock(&open_mutex); | 335 | mutex_lock(&HOSTFS_I(ino)->open_mutex); |
328 | /* somebody else had handled it first? */ | 336 | /* somebody else had handled it first? */ |
329 | if ((mode & HOSTFS_I(ino)->mode) == mode) { | 337 | if ((mode & HOSTFS_I(ino)->mode) == mode) { |
330 | mutex_unlock(&open_mutex); | 338 | mutex_unlock(&HOSTFS_I(ino)->open_mutex); |
339 | close_file(&fd); | ||
331 | return 0; | 340 | return 0; |
332 | } | 341 | } |
333 | if ((mode | HOSTFS_I(ino)->mode) != mode) { | 342 | if ((mode | HOSTFS_I(ino)->mode) != mode) { |
334 | mode |= HOSTFS_I(ino)->mode; | 343 | mode |= HOSTFS_I(ino)->mode; |
335 | mutex_unlock(&open_mutex); | 344 | mutex_unlock(&HOSTFS_I(ino)->open_mutex); |
336 | close_file(&fd); | 345 | close_file(&fd); |
337 | goto retry; | 346 | goto retry; |
338 | } | 347 | } |
@@ -342,12 +351,12 @@ retry: | |||
342 | err = replace_file(fd, HOSTFS_I(ino)->fd); | 351 | err = replace_file(fd, HOSTFS_I(ino)->fd); |
343 | close_file(&fd); | 352 | close_file(&fd); |
344 | if (err < 0) { | 353 | if (err < 0) { |
345 | mutex_unlock(&open_mutex); | 354 | mutex_unlock(&HOSTFS_I(ino)->open_mutex); |
346 | return err; | 355 | return err; |
347 | } | 356 | } |
348 | } | 357 | } |
349 | HOSTFS_I(ino)->mode = mode; | 358 | HOSTFS_I(ino)->mode = mode; |
350 | mutex_unlock(&open_mutex); | 359 | mutex_unlock(&HOSTFS_I(ino)->open_mutex); |
351 | 360 | ||
352 | return 0; | 361 | return 0; |
353 | } | 362 | } |
@@ -382,7 +391,7 @@ static const struct file_operations hostfs_file_fops = { | |||
382 | .read_iter = generic_file_read_iter, | 391 | .read_iter = generic_file_read_iter, |
383 | .write_iter = generic_file_write_iter, | 392 | .write_iter = generic_file_write_iter, |
384 | .mmap = generic_file_mmap, | 393 | .mmap = generic_file_mmap, |
385 | .open = hostfs_file_open, | 394 | .open = hostfs_open, |
386 | .release = hostfs_file_release, | 395 | .release = hostfs_file_release, |
387 | .fsync = hostfs_fsync, | 396 | .fsync = hostfs_fsync, |
388 | }; | 397 | }; |
@@ -391,6 +400,8 @@ static const struct file_operations hostfs_dir_fops = { | |||
391 | .llseek = generic_file_llseek, | 400 | .llseek = generic_file_llseek, |
392 | .iterate = hostfs_readdir, | 401 | .iterate = hostfs_readdir, |
393 | .read = generic_read_dir, | 402 | .read = generic_read_dir, |
403 | .open = hostfs_open, | ||
404 | .fsync = hostfs_fsync, | ||
394 | }; | 405 | }; |
395 | 406 | ||
396 | static int hostfs_writepage(struct page *page, struct writeback_control *wbc) | 407 | static int hostfs_writepage(struct page *page, struct writeback_control *wbc) |
@@ -398,7 +409,7 @@ static int hostfs_writepage(struct page *page, struct writeback_control *wbc) | |||
398 | struct address_space *mapping = page->mapping; | 409 | struct address_space *mapping = page->mapping; |
399 | struct inode *inode = mapping->host; | 410 | struct inode *inode = mapping->host; |
400 | char *buffer; | 411 | char *buffer; |
401 | unsigned long long base; | 412 | loff_t base = page_offset(page); |
402 | int count = PAGE_CACHE_SIZE; | 413 | int count = PAGE_CACHE_SIZE; |
403 | int end_index = inode->i_size >> PAGE_CACHE_SHIFT; | 414 | int end_index = inode->i_size >> PAGE_CACHE_SHIFT; |
404 | int err; | 415 | int err; |
@@ -407,7 +418,6 @@ static int hostfs_writepage(struct page *page, struct writeback_control *wbc) | |||
407 | count = inode->i_size & (PAGE_CACHE_SIZE-1); | 418 | count = inode->i_size & (PAGE_CACHE_SIZE-1); |
408 | 419 | ||
409 | buffer = kmap(page); | 420 | buffer = kmap(page); |
410 | base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; | ||
411 | 421 | ||
412 | err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count); | 422 | err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count); |
413 | if (err != count) { | 423 | if (err != count) { |
@@ -432,26 +442,29 @@ static int hostfs_writepage(struct page *page, struct writeback_control *wbc) | |||
432 | static int hostfs_readpage(struct file *file, struct page *page) | 442 | static int hostfs_readpage(struct file *file, struct page *page) |
433 | { | 443 | { |
434 | char *buffer; | 444 | char *buffer; |
435 | long long start; | 445 | loff_t start = page_offset(page); |
436 | int err = 0; | 446 | int bytes_read, ret = 0; |
437 | 447 | ||
438 | start = (long long) page->index << PAGE_CACHE_SHIFT; | ||
439 | buffer = kmap(page); | 448 | buffer = kmap(page); |
440 | err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer, | 449 | bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer, |
441 | PAGE_CACHE_SIZE); | 450 | PAGE_CACHE_SIZE); |
442 | if (err < 0) | 451 | if (bytes_read < 0) { |
452 | ClearPageUptodate(page); | ||
453 | SetPageError(page); | ||
454 | ret = bytes_read; | ||
443 | goto out; | 455 | goto out; |
456 | } | ||
444 | 457 | ||
445 | memset(&buffer[err], 0, PAGE_CACHE_SIZE - err); | 458 | memset(buffer + bytes_read, 0, PAGE_CACHE_SIZE - bytes_read); |
446 | 459 | ||
447 | flush_dcache_page(page); | 460 | ClearPageError(page); |
448 | SetPageUptodate(page); | 461 | SetPageUptodate(page); |
449 | if (PageError(page)) ClearPageError(page); | 462 | |
450 | err = 0; | ||
451 | out: | 463 | out: |
464 | flush_dcache_page(page); | ||
452 | kunmap(page); | 465 | kunmap(page); |
453 | unlock_page(page); | 466 | unlock_page(page); |
454 | return err; | 467 | return ret; |
455 | } | 468 | } |
456 | 469 | ||
457 | static int hostfs_write_begin(struct file *file, struct address_space *mapping, | 470 | static int hostfs_write_begin(struct file *file, struct address_space *mapping, |
@@ -528,11 +541,13 @@ static int read_name(struct inode *ino, char *name) | |||
528 | init_special_inode(ino, st.mode & S_IFMT, rdev); | 541 | init_special_inode(ino, st.mode & S_IFMT, rdev); |
529 | ino->i_op = &hostfs_iops; | 542 | ino->i_op = &hostfs_iops; |
530 | break; | 543 | break; |
531 | 544 | case S_IFREG: | |
532 | default: | ||
533 | ino->i_op = &hostfs_iops; | 545 | ino->i_op = &hostfs_iops; |
534 | ino->i_fop = &hostfs_file_fops; | 546 | ino->i_fop = &hostfs_file_fops; |
535 | ino->i_mapping->a_ops = &hostfs_aops; | 547 | ino->i_mapping->a_ops = &hostfs_aops; |
548 | break; | ||
549 | default: | ||
550 | return -EIO; | ||
536 | } | 551 | } |
537 | 552 | ||
538 | ino->i_ino = st.ino; | 553 | ino->i_ino = st.ino; |
@@ -566,10 +581,7 @@ static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
566 | if (name == NULL) | 581 | if (name == NULL) |
567 | goto out_put; | 582 | goto out_put; |
568 | 583 | ||
569 | fd = file_create(name, | 584 | fd = file_create(name, mode & S_IFMT); |
570 | mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR, | ||
571 | mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP, | ||
572 | mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH); | ||
573 | if (fd < 0) | 585 | if (fd < 0) |
574 | error = fd; | 586 | error = fd; |
575 | else | 587 | else |