at v3.2 1101 lines 26 kB view raw
1/* 2 * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> 3 * All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16#include <linux/kernel.h> 17#include <linux/fs.h> 18#include <linux/jhash.h> 19#include <linux/namei.h> 20#include <linux/slab.h> 21#include <linux/pagemap.h> 22 23#include "netfs.h" 24 25static int pohmelfs_cmp_hash(struct pohmelfs_name *n, u32 hash) 26{ 27 if (n->hash > hash) 28 return -1; 29 if (n->hash < hash) 30 return 1; 31 32 return 0; 33} 34 35static struct pohmelfs_name *pohmelfs_search_hash_unprecise(struct pohmelfs_inode *pi, u32 hash) 36{ 37 struct rb_node *n = pi->hash_root.rb_node; 38 struct pohmelfs_name *tmp = NULL; 39 int cmp; 40 41 while (n) { 42 tmp = rb_entry(n, struct pohmelfs_name, hash_node); 43 44 cmp = pohmelfs_cmp_hash(tmp, hash); 45 if (cmp < 0) 46 n = n->rb_left; 47 else if (cmp > 0) 48 n = n->rb_right; 49 else 50 break; 51 52 } 53 54 return tmp; 55} 56 57struct pohmelfs_name *pohmelfs_search_hash(struct pohmelfs_inode *pi, u32 hash) 58{ 59 struct pohmelfs_name *tmp; 60 61 tmp = pohmelfs_search_hash_unprecise(pi, hash); 62 if (tmp && (tmp->hash == hash)) 63 return tmp; 64 65 return NULL; 66} 67 68static void __pohmelfs_name_del(struct pohmelfs_inode *parent, struct pohmelfs_name *node) 69{ 70 rb_erase(&node->hash_node, &parent->hash_root); 71} 72 73/* 74 * Remove name cache entry from its caches and free it. 75 */ 76static void pohmelfs_name_free(struct pohmelfs_inode *parent, struct pohmelfs_name *node) 77{ 78 __pohmelfs_name_del(parent, node); 79 list_del(&node->sync_create_entry); 80 kfree(node); 81} 82 83static struct pohmelfs_name *pohmelfs_insert_hash(struct pohmelfs_inode *pi, 84 struct pohmelfs_name *new) 85{ 86 struct rb_node **n = &pi->hash_root.rb_node, *parent = NULL; 87 struct pohmelfs_name *ret = NULL, *tmp; 88 int cmp; 89 90 while (*n) { 91 parent = *n; 92 93 tmp = rb_entry(parent, struct pohmelfs_name, hash_node); 94 95 cmp = pohmelfs_cmp_hash(tmp, new->hash); 96 if (cmp < 0) 97 n = &parent->rb_left; 98 else if (cmp > 0) 99 n = &parent->rb_right; 100 else { 101 ret = tmp; 102 break; 103 } 104 } 105 106 if (ret) { 107 printk("%s: exist: parent: %llu, ino: %llu, hash: %x, len: %u, data: '%s', " 108 "new: ino: %llu, hash: %x, len: %u, data: '%s'.\n", 109 __func__, pi->ino, 110 ret->ino, ret->hash, ret->len, ret->data, 111 new->ino, new->hash, new->len, new->data); 112 ret->ino = new->ino; 113 return ret; 114 } 115 116 rb_link_node(&new->hash_node, parent, n); 117 rb_insert_color(&new->hash_node, &pi->hash_root); 118 119 return NULL; 120} 121 122/* 123 * Free name cache for given inode. 124 */ 125void pohmelfs_free_names(struct pohmelfs_inode *parent) 126{ 127 struct rb_node *rb_node; 128 struct pohmelfs_name *n; 129 130 for (rb_node = rb_first(&parent->hash_root); rb_node;) { 131 n = rb_entry(rb_node, struct pohmelfs_name, hash_node); 132 rb_node = rb_next(rb_node); 133 134 pohmelfs_name_free(parent, n); 135 } 136} 137 138static void pohmelfs_fix_offset(struct pohmelfs_inode *parent, struct pohmelfs_name *node) 139{ 140 parent->total_len -= node->len; 141} 142 143/* 144 * Free name cache entry helper. 145 */ 146void pohmelfs_name_del(struct pohmelfs_inode *parent, struct pohmelfs_name *node) 147{ 148 pohmelfs_fix_offset(parent, node); 149 pohmelfs_name_free(parent, node); 150} 151 152/* 153 * Insert new name cache entry into all hash cache. 154 */ 155static int pohmelfs_insert_name(struct pohmelfs_inode *parent, struct pohmelfs_name *n) 156{ 157 struct pohmelfs_name *name; 158 159 name = pohmelfs_insert_hash(parent, n); 160 if (name) 161 return -EEXIST; 162 163 parent->total_len += n->len; 164 list_add_tail(&n->sync_create_entry, &parent->sync_create_list); 165 166 return 0; 167} 168 169/* 170 * Allocate new name cache entry. 171 */ 172static struct pohmelfs_name *pohmelfs_name_alloc(unsigned int len) 173{ 174 struct pohmelfs_name *n; 175 176 n = kzalloc(sizeof(struct pohmelfs_name) + len, GFP_KERNEL); 177 if (!n) 178 return NULL; 179 180 INIT_LIST_HEAD(&n->sync_create_entry); 181 182 n->data = (char *)(n+1); 183 184 return n; 185} 186 187/* 188 * Add new name entry into directory's cache. 189 */ 190static int pohmelfs_add_dir(struct pohmelfs_sb *psb, struct pohmelfs_inode *parent, 191 struct pohmelfs_inode *npi, struct qstr *str, unsigned int mode, int link) 192{ 193 int err = -ENOMEM; 194 struct pohmelfs_name *n; 195 196 n = pohmelfs_name_alloc(str->len + 1); 197 if (!n) 198 goto err_out_exit; 199 200 n->ino = npi->ino; 201 n->mode = mode; 202 n->len = str->len; 203 n->hash = str->hash; 204 sprintf(n->data, "%s", str->name); 205 206 mutex_lock(&parent->offset_lock); 207 err = pohmelfs_insert_name(parent, n); 208 mutex_unlock(&parent->offset_lock); 209 210 if (err) { 211 if (err != -EEXIST) 212 goto err_out_free; 213 kfree(n); 214 } 215 216 return 0; 217 218err_out_free: 219 kfree(n); 220err_out_exit: 221 return err; 222} 223 224/* 225 * Create new inode for given parameters (name, inode info, parent). 226 * This does not create object on the server, it will be synced there during writeback. 227 */ 228struct pohmelfs_inode *pohmelfs_new_inode(struct pohmelfs_sb *psb, 229 struct pohmelfs_inode *parent, struct qstr *str, 230 struct netfs_inode_info *info, int link) 231{ 232 struct inode *new = NULL; 233 struct pohmelfs_inode *npi; 234 int err = -EEXIST; 235 236 dprintk("%s: creating inode: parent: %llu, ino: %llu, str: %p.\n", 237 __func__, (parent) ? parent->ino : 0, info->ino, str); 238 239 err = -ENOMEM; 240 new = iget_locked(psb->sb, info->ino); 241 if (!new) 242 goto err_out_exit; 243 244 npi = POHMELFS_I(new); 245 npi->ino = info->ino; 246 err = 0; 247 248 if (new->i_state & I_NEW) { 249 dprintk("%s: filling VFS inode: %lu/%llu.\n", 250 __func__, new->i_ino, info->ino); 251 pohmelfs_fill_inode(new, info); 252 253 if (S_ISDIR(info->mode)) { 254 struct qstr s; 255 256 s.name = "."; 257 s.len = 1; 258 s.hash = jhash(s.name, s.len, 0); 259 260 err = pohmelfs_add_dir(psb, npi, npi, &s, info->mode, 0); 261 if (err) 262 goto err_out_put; 263 264 s.name = ".."; 265 s.len = 2; 266 s.hash = jhash(s.name, s.len, 0); 267 268 err = pohmelfs_add_dir(psb, npi, (parent) ? parent : npi, &s, 269 (parent) ? parent->vfs_inode.i_mode : npi->vfs_inode.i_mode, 0); 270 if (err) 271 goto err_out_put; 272 } 273 } 274 275 if (str) { 276 if (parent) { 277 err = pohmelfs_add_dir(psb, parent, npi, str, info->mode, link); 278 279 dprintk("%s: %s inserted name: '%s', new_offset: %llu, ino: %llu, parent: %llu.\n", 280 __func__, (err) ? "unsuccessfully" : "successfully", 281 str->name, parent->total_len, info->ino, parent->ino); 282 283 if (err && err != -EEXIST) 284 goto err_out_put; 285 } 286 } 287 288 if (new->i_state & I_NEW) { 289 if (parent) 290 mark_inode_dirty(&parent->vfs_inode); 291 mark_inode_dirty(new); 292 } 293 294 set_bit(NETFS_INODE_OWNED, &npi->state); 295 npi->lock_type = POHMELFS_WRITE_LOCK; 296 unlock_new_inode(new); 297 298 return npi; 299 300err_out_put: 301 printk("%s: putting inode: %p, npi: %p, error: %d.\n", __func__, new, npi, err); 302 iput(new); 303err_out_exit: 304 return ERR_PTR(err); 305} 306 307static int pohmelfs_remote_sync_complete(struct page **pages, unsigned int page_num, 308 void *private, int err) 309{ 310 struct pohmelfs_inode *pi = private; 311 struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb); 312 313 dprintk("%s: ino: %llu, err: %d.\n", __func__, pi->ino, err); 314 315 if (err) 316 pi->error = err; 317 wake_up(&psb->wait); 318 pohmelfs_put_inode(pi); 319 320 return err; 321} 322 323/* 324 * Receive directory content from the server. 325 * This should be only done for objects, which were not created locally, 326 * and which were not synced previously. 327 */ 328static int pohmelfs_sync_remote_dir(struct pohmelfs_inode *pi) 329{ 330 struct inode *inode = &pi->vfs_inode; 331 struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb); 332 long ret = psb->wait_on_page_timeout; 333 int err; 334 335 dprintk("%s: dir: %llu, state: %lx: remote_synced: %d.\n", 336 __func__, pi->ino, pi->state, test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state)); 337 338 if (test_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state)) 339 return 0; 340 341 if (!igrab(inode)) { 342 err = -ENOENT; 343 goto err_out_exit; 344 } 345 346 err = pohmelfs_meta_command(pi, NETFS_READDIR, NETFS_TRANS_SINGLE_DST, 347 pohmelfs_remote_sync_complete, pi, 0); 348 if (err) 349 goto err_out_exit; 350 351 pi->error = 0; 352 ret = wait_event_interruptible_timeout(psb->wait, 353 test_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &pi->state) || pi->error, ret); 354 dprintk("%s: awake dir: %llu, ret: %ld, err: %d.\n", __func__, pi->ino, ret, pi->error); 355 if (ret <= 0) { 356 err = ret; 357 if (!err) 358 err = -ETIMEDOUT; 359 goto err_out_exit; 360 } 361 362 if (pi->error) 363 return pi->error; 364 365 return 0; 366 367err_out_exit: 368 clear_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state); 369 370 return err; 371} 372 373static int pohmelfs_dir_open(struct inode *inode, struct file *file) 374{ 375 file->private_data = NULL; 376 return 0; 377} 378 379/* 380 * VFS readdir callback. Syncs directory content from server if needed, 381 * and provides direntry info to the userspace. 382 */ 383static int pohmelfs_readdir(struct file *file, void *dirent, filldir_t filldir) 384{ 385 struct inode *inode = file->f_path.dentry->d_inode; 386 struct pohmelfs_inode *pi = POHMELFS_I(inode); 387 struct pohmelfs_name *n; 388 struct rb_node *rb_node; 389 int err = 0, mode; 390 u64 len; 391 392 dprintk("%s: parent: %llu, fpos: %llu, hash: %08lx.\n", 393 __func__, pi->ino, (u64)file->f_pos, 394 (unsigned long)file->private_data); 395#if 0 396 err = pohmelfs_data_lock(pi, 0, ~0, POHMELFS_READ_LOCK); 397 if (err) 398 return err; 399#endif 400 err = pohmelfs_sync_remote_dir(pi); 401 if (err) 402 return err; 403 404 if (file->private_data && (file->private_data == (void *)(unsigned long)file->f_pos)) 405 return 0; 406 407 mutex_lock(&pi->offset_lock); 408 n = pohmelfs_search_hash_unprecise(pi, (unsigned long)file->private_data); 409 410 while (n) { 411 mode = (n->mode >> 12) & 15; 412 413 dprintk("%s: offset: %llu, parent ino: %llu, name: '%s', len: %u, ino: %llu, " 414 "mode: %o/%o, fpos: %llu, hash: %08x.\n", 415 __func__, file->f_pos, pi->ino, n->data, n->len, 416 n->ino, n->mode, mode, file->f_pos, n->hash); 417 418 file->private_data = (void *)(unsigned long)n->hash; 419 420 len = n->len; 421 err = filldir(dirent, n->data, n->len, file->f_pos, n->ino, mode); 422 423 if (err < 0) { 424 dprintk("%s: err: %d.\n", __func__, err); 425 err = 0; 426 break; 427 } 428 429 file->f_pos += len; 430 431 rb_node = rb_next(&n->hash_node); 432 433 if (!rb_node || (rb_node == &n->hash_node)) { 434 file->private_data = (void *)(unsigned long)file->f_pos; 435 break; 436 } 437 438 n = rb_entry(rb_node, struct pohmelfs_name, hash_node); 439 } 440 mutex_unlock(&pi->offset_lock); 441 442 return err; 443} 444 445static loff_t pohmelfs_dir_lseek(struct file *file, loff_t offset, int origin) 446{ 447 file->f_pos = offset; 448 file->private_data = NULL; 449 return offset; 450} 451 452const struct file_operations pohmelfs_dir_fops = { 453 .open = pohmelfs_dir_open, 454 .read = generic_read_dir, 455 .llseek = pohmelfs_dir_lseek, 456 .readdir = pohmelfs_readdir, 457}; 458 459/* 460 * Lookup single object on server. 461 */ 462static int pohmelfs_lookup_single(struct pohmelfs_inode *parent, 463 struct qstr *str, u64 ino) 464{ 465 struct pohmelfs_sb *psb = POHMELFS_SB(parent->vfs_inode.i_sb); 466 long ret = msecs_to_jiffies(5000); 467 int err; 468 469 set_bit(NETFS_COMMAND_PENDING, &parent->state); 470 err = pohmelfs_meta_command_data(parent, parent->ino, NETFS_LOOKUP, 471 (char *)str->name, NETFS_TRANS_SINGLE_DST, NULL, NULL, ino); 472 if (err) 473 goto err_out_exit; 474 475 err = 0; 476 ret = wait_event_interruptible_timeout(psb->wait, 477 !test_bit(NETFS_COMMAND_PENDING, &parent->state), ret); 478 if (ret <= 0) { 479 err = ret; 480 if (!err) 481 err = -ETIMEDOUT; 482 } 483 484 if (err) 485 goto err_out_exit; 486 487 return 0; 488 489err_out_exit: 490 clear_bit(NETFS_COMMAND_PENDING, &parent->state); 491 492 printk("%s: failed: parent: %llu, ino: %llu, name: '%s', err: %d.\n", 493 __func__, parent->ino, ino, str->name, err); 494 495 return err; 496} 497 498/* 499 * VFS lookup callback. 500 * We first try to get inode number from local name cache, if we have one, 501 * then inode can be found in inode cache. If there is no inode or no object in 502 * local cache, try to lookup it on server. This only should be done for directories, 503 * which were not created locally, otherwise remote server does not know about dir at all, 504 * so no need to try to know that. 505 */ 506struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 507{ 508 struct pohmelfs_inode *parent = POHMELFS_I(dir); 509 struct pohmelfs_name *n; 510 struct inode *inode = NULL; 511 unsigned long ino = 0; 512 int err, lock_type = POHMELFS_READ_LOCK, need_lock = 1; 513 struct qstr str = dentry->d_name; 514 515 if ((nd->intent.open.flags & O_ACCMODE) != O_RDONLY) 516 lock_type = POHMELFS_WRITE_LOCK; 517 518 if (test_bit(NETFS_INODE_OWNED, &parent->state)) { 519 if (lock_type == parent->lock_type) 520 need_lock = 0; 521 if ((lock_type == POHMELFS_READ_LOCK) && (parent->lock_type == POHMELFS_WRITE_LOCK)) 522 need_lock = 0; 523 } 524 525 if ((lock_type == POHMELFS_READ_LOCK) && !test_bit(NETFS_INODE_REMOTE_DIR_SYNCED, &parent->state)) 526 need_lock = 1; 527 528 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0); 529 530 mutex_lock(&parent->offset_lock); 531 n = pohmelfs_search_hash(parent, str.hash); 532 if (n) 533 ino = n->ino; 534 mutex_unlock(&parent->offset_lock); 535 536 dprintk("%s: start ino: %lu, inode: %p, name: '%s', hash: %x, parent_state: %lx, need_lock: %d.\n", 537 __func__, ino, inode, str.name, str.hash, parent->state, need_lock); 538 539 if (ino) { 540 inode = ilookup(dir->i_sb, ino); 541 if (inode) 542 goto out; 543 } 544 545 dprintk("%s: no inode dir: %p, dir_ino: %llu, name: '%s', len: %u, dir_state: %lx, ino: %lu.\n", 546 __func__, dir, parent->ino, 547 str.name, str.len, parent->state, ino); 548 549 if (!ino) { 550 if (!need_lock) 551 goto out; 552 } 553 554 err = pohmelfs_data_lock(parent, 0, ~0, lock_type); 555 if (err) 556 goto out; 557 558 err = pohmelfs_lookup_single(parent, &str, ino); 559 if (err) 560 goto out; 561 562 if (!ino) { 563 mutex_lock(&parent->offset_lock); 564 n = pohmelfs_search_hash(parent, str.hash); 565 if (n) 566 ino = n->ino; 567 mutex_unlock(&parent->offset_lock); 568 } 569 570 if (ino) { 571 inode = ilookup(dir->i_sb, ino); 572 dprintk("%s: second lookup ino: %lu, inode: %p, name: '%s', hash: %x.\n", 573 __func__, ino, inode, str.name, str.hash); 574 if (!inode) { 575 dprintk("%s: No inode for ino: %lu, name: '%s', hash: %x.\n", 576 __func__, ino, str.name, str.hash); 577 /* return NULL; */ 578 return ERR_PTR(-EACCES); 579 } 580 } else { 581 printk("%s: No inode number : name: '%s', hash: %x.\n", 582 __func__, str.name, str.hash); 583 } 584out: 585 return d_splice_alias(inode, dentry); 586} 587 588/* 589 * Create new object in local cache. Object will be synced to server 590 * during writeback for given inode. 591 */ 592struct pohmelfs_inode *pohmelfs_create_entry_local(struct pohmelfs_sb *psb, 593 struct pohmelfs_inode *parent, struct qstr *str, u64 start, int mode) 594{ 595 struct pohmelfs_inode *npi; 596 int err = -ENOMEM; 597 struct netfs_inode_info info; 598 599 dprintk("%s: name: '%s', mode: %o, start: %llu.\n", 600 __func__, str->name, mode, start); 601 602 info.mode = mode; 603 info.ino = start; 604 605 if (!start) 606 info.ino = pohmelfs_new_ino(psb); 607 608 info.nlink = S_ISDIR(mode) ? 2 : 1; 609 info.uid = current_fsuid(); 610 info.gid = current_fsgid(); 611 info.size = 0; 612 info.blocksize = 512; 613 info.blocks = 0; 614 info.rdev = 0; 615 info.version = 0; 616 617 npi = pohmelfs_new_inode(psb, parent, str, &info, !!start); 618 if (IS_ERR(npi)) { 619 err = PTR_ERR(npi); 620 goto err_out_unlock; 621 } 622 623 return npi; 624 625err_out_unlock: 626 dprintk("%s: err: %d.\n", __func__, err); 627 return ERR_PTR(err); 628} 629 630/* 631 * Create local object and bind it to dentry. 632 */ 633static int pohmelfs_create_entry(struct inode *dir, struct dentry *dentry, u64 start, int mode) 634{ 635 struct pohmelfs_sb *psb = POHMELFS_SB(dir->i_sb); 636 struct pohmelfs_inode *npi, *parent; 637 struct qstr str = dentry->d_name; 638 int err; 639 640 parent = POHMELFS_I(dir); 641 642 err = pohmelfs_data_lock(parent, 0, ~0, POHMELFS_WRITE_LOCK); 643 if (err) 644 return err; 645 646 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0); 647 648 npi = pohmelfs_create_entry_local(psb, parent, &str, start, mode); 649 if (IS_ERR(npi)) 650 return PTR_ERR(npi); 651 652 d_instantiate(dentry, &npi->vfs_inode); 653 654 dprintk("%s: parent: %llu, inode: %llu, name: '%s', parent_nlink: %d, nlink: %d.\n", 655 __func__, parent->ino, npi->ino, dentry->d_name.name, 656 (signed)dir->i_nlink, (signed)npi->vfs_inode.i_nlink); 657 658 return 0; 659} 660 661/* 662 * VFS create and mkdir callbacks. 663 */ 664static int pohmelfs_create(struct inode *dir, struct dentry *dentry, int mode, 665 struct nameidata *nd) 666{ 667 return pohmelfs_create_entry(dir, dentry, 0, mode); 668} 669 670static int pohmelfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 671{ 672 int err; 673 674 inode_inc_link_count(dir); 675 err = pohmelfs_create_entry(dir, dentry, 0, mode | S_IFDIR); 676 if (err) 677 inode_dec_link_count(dir); 678 679 return err; 680} 681 682static int pohmelfs_remove_entry(struct inode *dir, struct dentry *dentry) 683{ 684 struct pohmelfs_sb *psb = POHMELFS_SB(dir->i_sb); 685 struct inode *inode = dentry->d_inode; 686 struct pohmelfs_inode *parent = POHMELFS_I(dir), *pi = POHMELFS_I(inode); 687 struct pohmelfs_name *n; 688 int err = -ENOENT; 689 struct qstr str = dentry->d_name; 690 691 err = pohmelfs_data_lock(parent, 0, ~0, POHMELFS_WRITE_LOCK); 692 if (err) 693 return err; 694 695 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0); 696 697 dprintk("%s: dir_ino: %llu, inode: %llu, name: '%s', nlink: %d.\n", 698 __func__, parent->ino, pi->ino, 699 str.name, (signed)inode->i_nlink); 700 701 BUG_ON(!inode); 702 703 mutex_lock(&parent->offset_lock); 704 n = pohmelfs_search_hash(parent, str.hash); 705 if (n) { 706 pohmelfs_fix_offset(parent, n); 707 if (test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state)) 708 pohmelfs_remove_child(pi, n); 709 710 pohmelfs_name_free(parent, n); 711 err = 0; 712 } 713 mutex_unlock(&parent->offset_lock); 714 715 if (!err) { 716 psb->avail_size += inode->i_size; 717 718 pohmelfs_inode_del_inode(psb, pi); 719 720 mark_inode_dirty(dir); 721 722 inode->i_ctime = dir->i_ctime; 723 if (inode->i_nlink) 724 inode_dec_link_count(inode); 725 } 726 727 return err; 728} 729 730/* 731 * Unlink and rmdir VFS callbacks. 732 */ 733static int pohmelfs_unlink(struct inode *dir, struct dentry *dentry) 734{ 735 return pohmelfs_remove_entry(dir, dentry); 736} 737 738static int pohmelfs_rmdir(struct inode *dir, struct dentry *dentry) 739{ 740 int err; 741 struct inode *inode = dentry->d_inode; 742 743 dprintk("%s: parent: %llu, inode: %llu, name: '%s', parent_nlink: %d, nlink: %d.\n", 744 __func__, POHMELFS_I(dir)->ino, POHMELFS_I(inode)->ino, 745 dentry->d_name.name, (signed)dir->i_nlink, (signed)inode->i_nlink); 746 747 err = pohmelfs_remove_entry(dir, dentry); 748 if (!err) { 749 inode_dec_link_count(dir); 750 inode_dec_link_count(inode); 751 } 752 753 return err; 754} 755 756/* 757 * Link creation is synchronous. 758 * I'm lazy. 759 * Earth is somewhat round. 760 */ 761static int pohmelfs_create_link(struct pohmelfs_inode *parent, struct qstr *obj, 762 struct pohmelfs_inode *target, struct qstr *tstr) 763{ 764 struct super_block *sb = parent->vfs_inode.i_sb; 765 struct pohmelfs_sb *psb = POHMELFS_SB(sb); 766 struct netfs_cmd *cmd; 767 struct netfs_trans *t; 768 void *data; 769 int err, parent_len, target_len = 0, cur_len, path_size = 0; 770 771 err = pohmelfs_data_lock(parent, 0, ~0, POHMELFS_WRITE_LOCK); 772 if (err) 773 return err; 774 775 err = sb->s_op->write_inode(&parent->vfs_inode, 0); 776 if (err) 777 goto err_out_exit; 778 779 if (tstr) 780 target_len = tstr->len; 781 782 parent_len = pohmelfs_path_length(parent); 783 if (target) 784 target_len += pohmelfs_path_length(target); 785 786 if (parent_len < 0) { 787 err = parent_len; 788 goto err_out_exit; 789 } 790 791 if (target_len < 0) { 792 err = target_len; 793 goto err_out_exit; 794 } 795 796 t = netfs_trans_alloc(psb, parent_len + target_len + obj->len + 2, 0, 0); 797 if (!t) { 798 err = -ENOMEM; 799 goto err_out_exit; 800 } 801 cur_len = netfs_trans_cur_len(t); 802 803 cmd = netfs_trans_current(t); 804 if (IS_ERR(cmd)) { 805 err = PTR_ERR(cmd); 806 goto err_out_free; 807 } 808 809 data = (void *)(cmd + 1); 810 cur_len -= sizeof(struct netfs_cmd); 811 812 err = pohmelfs_construct_path_string(parent, data, parent_len); 813 if (err > 0) { 814 /* Do not place null-byte before the slash */ 815 path_size = err - 1; 816 cur_len -= path_size; 817 818 err = snprintf(data + path_size, cur_len, "/%s|", obj->name); 819 820 path_size += err; 821 cur_len -= err; 822 823 cmd->ext = path_size - 1; /* No | symbol */ 824 825 if (target) { 826 err = pohmelfs_construct_path_string(target, data + path_size, target_len); 827 if (err > 0) { 828 path_size += err; 829 cur_len -= err; 830 } 831 } 832 } 833 834 if (err < 0) 835 goto err_out_free; 836 837 cmd->start = 0; 838 839 if (!target && tstr) { 840 if (tstr->len > cur_len - 1) { 841 err = -ENAMETOOLONG; 842 goto err_out_free; 843 } 844 845 err = snprintf(data + path_size, cur_len, "%s", tstr->name) + 1; /* 0-byte */ 846 path_size += err; 847 cur_len -= err; 848 cmd->start = 1; 849 } 850 851 dprintk("%s: parent: %llu, obj: '%s', target_inode: %llu, target_str: '%s', full: '%s'.\n", 852 __func__, parent->ino, obj->name, (target) ? target->ino : 0, (tstr) ? tstr->name : NULL, 853 (char *)data); 854 855 cmd->cmd = NETFS_LINK; 856 cmd->size = path_size; 857 cmd->id = parent->ino; 858 859 netfs_convert_cmd(cmd); 860 861 netfs_trans_update(cmd, t, path_size); 862 863 err = netfs_trans_finish(t, psb); 864 if (err) 865 goto err_out_exit; 866 867 return 0; 868 869err_out_free: 870 t->result = err; 871 netfs_trans_put(t); 872err_out_exit: 873 return err; 874} 875 876/* 877 * VFS hard and soft link callbacks. 878 */ 879static int pohmelfs_link(struct dentry *old_dentry, struct inode *dir, 880 struct dentry *dentry) 881{ 882 struct inode *inode = old_dentry->d_inode; 883 struct pohmelfs_inode *pi = POHMELFS_I(inode); 884 int err; 885 struct qstr str = dentry->d_name; 886 887 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0); 888 889 err = inode->i_sb->s_op->write_inode(inode, 0); 890 if (err) 891 return err; 892 893 err = pohmelfs_create_link(POHMELFS_I(dir), &str, pi, NULL); 894 if (err) 895 return err; 896 897 return pohmelfs_create_entry(dir, dentry, pi->ino, inode->i_mode); 898} 899 900static int pohmelfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 901{ 902 struct qstr sym_str; 903 struct qstr str = dentry->d_name; 904 struct inode *inode; 905 int err; 906 907 str.hash = jhash(dentry->d_name.name, dentry->d_name.len, 0); 908 909 sym_str.name = symname; 910 sym_str.len = strlen(symname); 911 912 err = pohmelfs_create_link(POHMELFS_I(dir), &str, NULL, &sym_str); 913 if (err) 914 goto err_out_exit; 915 916 err = pohmelfs_create_entry(dir, dentry, 0, S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); 917 if (err) 918 goto err_out_exit; 919 920 inode = dentry->d_inode; 921 922 err = page_symlink(inode, symname, sym_str.len + 1); 923 if (err) 924 goto err_out_put; 925 926 return 0; 927 928err_out_put: 929 iput(inode); 930err_out_exit: 931 return err; 932} 933 934static int pohmelfs_send_rename(struct pohmelfs_inode *pi, struct pohmelfs_inode *parent, 935 struct qstr *str) 936{ 937 int path_len, err, total_len = 0, inode_len, parent_len; 938 char *path; 939 struct netfs_trans *t; 940 struct netfs_cmd *cmd; 941 struct pohmelfs_sb *psb = POHMELFS_SB(pi->vfs_inode.i_sb); 942 943 parent_len = pohmelfs_path_length(parent); 944 inode_len = pohmelfs_path_length(pi); 945 946 if (parent_len < 0 || inode_len < 0) 947 return -EINVAL; 948 949 path_len = parent_len + inode_len + str->len + 3; 950 951 t = netfs_trans_alloc(psb, path_len, 0, 0); 952 if (!t) 953 return -ENOMEM; 954 955 cmd = netfs_trans_current(t); 956 path = (char *)(cmd + 1); 957 958 err = pohmelfs_construct_path_string(pi, path, inode_len); 959 if (err < 0) 960 goto err_out_unlock; 961 962 cmd->ext = err; 963 964 path += err; 965 total_len += err; 966 path_len -= err; 967 968 *path = '|'; 969 path++; 970 total_len++; 971 path_len--; 972 973 err = pohmelfs_construct_path_string(parent, path, parent_len); 974 if (err < 0) 975 goto err_out_unlock; 976 977 /* 978 * Do not place a null-byte before the final slash and the name. 979 */ 980 err--; 981 path += err; 982 total_len += err; 983 path_len -= err; 984 985 err = snprintf(path, path_len - 1, "/%s", str->name); 986 987 total_len += err + 1; /* 0 symbol */ 988 path_len -= err + 1; 989 990 cmd->cmd = NETFS_RENAME; 991 cmd->id = pi->ino; 992 cmd->start = parent->ino; 993 cmd->size = total_len; 994 995 netfs_convert_cmd(cmd); 996 997 netfs_trans_update(cmd, t, total_len); 998 999 return netfs_trans_finish(t, psb); 1000 1001err_out_unlock: 1002 netfs_trans_free(t); 1003 return err; 1004} 1005 1006static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry, 1007 struct inode *new_dir, struct dentry *new_dentry) 1008{ 1009 struct inode *inode = old_dentry->d_inode; 1010 struct pohmelfs_inode *old_parent, *pi, *new_parent; 1011 struct qstr str = new_dentry->d_name; 1012 struct pohmelfs_name *n; 1013 unsigned int old_hash; 1014 int err = -ENOENT; 1015 1016 pi = POHMELFS_I(inode); 1017 old_parent = POHMELFS_I(old_dir); 1018 1019 if (new_dir) 1020 new_dir->i_sb->s_op->write_inode(new_dir, 0); 1021 1022 old_hash = jhash(old_dentry->d_name.name, old_dentry->d_name.len, 0); 1023 str.hash = jhash(new_dentry->d_name.name, new_dentry->d_name.len, 0); 1024 1025 str.len = new_dentry->d_name.len; 1026 str.name = new_dentry->d_name.name; 1027 str.hash = jhash(new_dentry->d_name.name, new_dentry->d_name.len, 0); 1028 1029 if (new_dir) { 1030 new_parent = POHMELFS_I(new_dir); 1031 err = -ENOTEMPTY; 1032 1033 if (S_ISDIR(inode->i_mode) && 1034 new_parent->total_len <= 3) 1035 goto err_out_exit; 1036 } else { 1037 new_parent = old_parent; 1038 } 1039 1040 dprintk("%s: ino: %llu, parent: %llu, name: '%s' -> parent: %llu, name: '%s', i_size: %llu.\n", 1041 __func__, pi->ino, old_parent->ino, old_dentry->d_name.name, 1042 new_parent->ino, new_dentry->d_name.name, inode->i_size); 1043 1044 if (test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state) && 1045 test_bit(NETFS_INODE_OWNED, &pi->state)) { 1046 err = pohmelfs_send_rename(pi, new_parent, &str); 1047 if (err) 1048 goto err_out_exit; 1049 } 1050 1051 n = pohmelfs_name_alloc(str.len + 1); 1052 if (!n) 1053 goto err_out_exit; 1054 1055 mutex_lock(&new_parent->offset_lock); 1056 n->ino = pi->ino; 1057 n->mode = inode->i_mode; 1058 n->len = str.len; 1059 n->hash = str.hash; 1060 sprintf(n->data, "%s", str.name); 1061 1062 err = pohmelfs_insert_name(new_parent, n); 1063 mutex_unlock(&new_parent->offset_lock); 1064 1065 if (err) 1066 goto err_out_exit; 1067 1068 mutex_lock(&old_parent->offset_lock); 1069 n = pohmelfs_search_hash(old_parent, old_hash); 1070 if (n) 1071 pohmelfs_name_del(old_parent, n); 1072 mutex_unlock(&old_parent->offset_lock); 1073 1074 mark_inode_dirty(inode); 1075 mark_inode_dirty(&new_parent->vfs_inode); 1076 1077 WARN_ON_ONCE(list_empty(&inode->i_dentry)); 1078 1079 return 0; 1080 1081err_out_exit: 1082 1083 clear_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state); 1084 1085 return err; 1086} 1087 1088/* 1089 * POHMELFS directory inode operations. 1090 */ 1091const struct inode_operations pohmelfs_dir_inode_ops = { 1092 .link = pohmelfs_link, 1093 .symlink = pohmelfs_symlink, 1094 .unlink = pohmelfs_unlink, 1095 .mkdir = pohmelfs_mkdir, 1096 .rmdir = pohmelfs_rmdir, 1097 .create = pohmelfs_create, 1098 .lookup = pohmelfs_lookup, 1099 .setattr = pohmelfs_setattr, 1100 .rename = pohmelfs_rename, 1101};