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