Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.9.4.
   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};