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/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) > 1)
 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        mutex_unlock(&inode->i_mutex);
1086        return err;
1087}
1088
1089/*
1090 * POHMELFS directory inode operations.
1091 */
1092const struct inode_operations pohmelfs_dir_inode_ops = {
1093        .link           = pohmelfs_link,
1094        .symlink        = pohmelfs_symlink,
1095        .unlink         = pohmelfs_unlink,
1096        .mkdir          = pohmelfs_mkdir,
1097        .rmdir          = pohmelfs_rmdir,
1098        .create         = pohmelfs_create,
1099        .lookup         = pohmelfs_lookup,
1100        .setattr        = pohmelfs_setattr,
1101        .rename         = pohmelfs_rename,
1102};
1103