Пример #1
0
static int au_dpages_append(struct au_dcsub_pages *dpages,
			    struct dentry *dentry, gfp_t gfp)
{
	int err, sz;
	struct au_dpage *dpage;
	void *p;

	dpage = dpages->dpages + dpages->ndpage - 1;
	sz = PAGE_SIZE / sizeof(dentry);
	if (unlikely(dpage->ndentry >= sz)) {
		AuLabel(new dpage);
		err = -ENOMEM;
		sz = dpages->ndpage * sizeof(*dpages->dpages);
		p = au_kzrealloc(dpages->dpages, sz,
				 sz + sizeof(*dpages->dpages), gfp);
		if (unlikely(!p))
			goto out;

		dpages->dpages = p;
		dpage = dpages->dpages + dpages->ndpage;
		p = (void *)__get_free_page(gfp);
		if (unlikely(!p))
			goto out;

		dpage->ndentry = 0;
		dpage->dentries = p;
		dpages->ndpage++;
	}

	AuDebugOn(!d_count(dentry));
	dpage->dentries[dpage->ndentry++] = dget_dlock(dentry);
	return 0; /* success */

out:
	return err;
}
Пример #2
0
/* Check if 'dentry' should expire, or return a nearby
 * dentry that is suitable.
 * If returned dentry is different from arg dentry,
 * then a dget() reference was taken, else not.
 */
static struct dentry *should_expire(struct dentry *dentry,
				    struct vfsmount *mnt,
				    unsigned long timeout,
				    int how)
{
	int do_now = how & AUTOFS_EXP_IMMEDIATE;
	int exp_leaves = how & AUTOFS_EXP_LEAVES;
	struct autofs_info *ino = autofs4_dentry_ino(dentry);
	unsigned int ino_count;

	/* No point expiring a pending mount */
	if (ino->flags & AUTOFS_INF_PENDING)
		return NULL;

	/*
	 * Case 1: (i) indirect mount or top level pseudo direct mount
	 *	   (autofs-4.1).
	 *	   (ii) indirect mount with offset mount, check the "/"
	 *	   offset (autofs-5.0+).
	 */
	if (d_mountpoint(dentry)) {
		pr_debug("checking mountpoint %p %pd\n", dentry, dentry);

		/* Can we umount this guy */
		if (autofs4_mount_busy(mnt, dentry))
			return NULL;

		/* Can we expire this guy */
		if (autofs4_can_expire(dentry, timeout, do_now))
			return dentry;
		return NULL;
	}

	if (d_really_is_positive(dentry) && d_is_symlink(dentry)) {
		pr_debug("checking symlink %p %pd\n", dentry, dentry);
		/*
		 * A symlink can't be "busy" in the usual sense so
		 * just check last used for expire timeout.
		 */
		if (autofs4_can_expire(dentry, timeout, do_now))
			return dentry;
		return NULL;
	}

	if (simple_empty(dentry))
		return NULL;

	/* Case 2: tree mount, expire iff entire tree is not busy */
	if (!exp_leaves) {
		/* Path walk currently on this dentry? */
		ino_count = atomic_read(&ino->count) + 1;
		if (d_count(dentry) > ino_count)
			return NULL;

		if (!autofs4_tree_busy(mnt, dentry, timeout, do_now))
			return dentry;
	/*
	 * Case 3: pseudo direct mount, expire individual leaves
	 *	   (autofs-4.1).
	 */
	} else {
		/* Path walk currently on this dentry? */
		struct dentry *expired;

		ino_count = atomic_read(&ino->count) + 1;
		if (d_count(dentry) > ino_count)
			return NULL;

		expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
		if (expired) {
			if (expired == dentry)
				dput(dentry);
			return expired;
		}
	}
	return NULL;
}
Пример #3
0
/* try d_walk() in linux/fs/dcache.c */
int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
		   au_dpages_test test, void *arg)
{
	int err;
	struct dentry *this_parent;
	struct list_head *next;
	struct super_block *sb = root->d_sb;

	err = 0;
	write_seqlock(&rename_lock);
	this_parent = root;
	spin_lock(&this_parent->d_lock);
repeat:
	next = this_parent->d_subdirs.next;
resume:
	if (this_parent->d_sb == sb
	    && !IS_ROOT(this_parent)
	    && au_di(this_parent)
	    && d_count(this_parent)
	    && (!test || test(this_parent, arg))) {
		err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
		if (unlikely(err))
			goto out;
	}

	while (next != &this_parent->d_subdirs) {
		struct list_head *tmp = next;
		struct dentry *dentry = list_entry(tmp, struct dentry,
						   d_u.d_child);

		next = tmp->next;
		spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
		if (d_count(dentry)) {
			if (!list_empty(&dentry->d_subdirs)) {
				spin_unlock(&this_parent->d_lock);
				spin_release(&dentry->d_lock.dep_map, 1,
					     _RET_IP_);
				this_parent = dentry;
				spin_acquire(&this_parent->d_lock.dep_map, 0, 1,
					     _RET_IP_);
				goto repeat;
			}
			if (dentry->d_sb == sb
			    && au_di(dentry)
			    && (!test || test(dentry, arg)))
				err = au_dpages_append(dpages, dentry,
						       GFP_ATOMIC);
		}
		spin_unlock(&dentry->d_lock);
		if (unlikely(err))
			goto out;
	}

	if (this_parent != root) {
		struct dentry *tmp;
		struct dentry *child;

		tmp = this_parent->d_parent;
		rcu_read_lock();
		spin_unlock(&this_parent->d_lock);
		child = this_parent;
		this_parent = tmp;
		spin_lock(&this_parent->d_lock);
		rcu_read_unlock();
		next = child->d_u.d_child.next;
		goto resume;
	}

out:
	spin_unlock(&this_parent->d_lock);
	write_sequnlock(&rename_lock);
	return err;
}
/**
 * nfs_sillyrename - Perform a silly-rename of a dentry
 * @dir: inode of directory that contains dentry
 * @dentry: dentry to be sillyrenamed
 *
 * NFSv2/3 is stateless and the server doesn't know when the client is
 * holding a file open. To prevent application problems when a file is
 * unlinked while it's still open, the client performs a "silly-rename".
 * That is, it renames the file to a hidden file in the same directory,
 * and only performs the unlink once the last reference to it is put.
 *
 * The final cleanup is done during dentry_iput.
 *
 * (Note: NFSv4 is stateful, and has opens, so in theory an NFSv4 server
 * could take responsibility for keeping open files referenced.  The server
 * would also need to ensure that opened-but-deleted files were kept over
 * reboots.  However, we may not assume a server does so.  (RFC 5661
 * does provide an OPEN4_RESULT_PRESERVE_UNLINKED flag that a server can
 * use to advertise that it does this; some day we may take advantage of
 * it.))
 */
int
nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
	static unsigned int sillycounter;
	unsigned char silly[SILLYNAME_LEN + 1];
	unsigned long long fileid;
	struct dentry *sdentry;
	struct rpc_task *task;
	int            error = -EBUSY;

	dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
		dentry->d_parent->d_name.name, dentry->d_name.name,
		d_count(dentry));
	nfs_inc_stats(dir, NFSIOS_SILLYRENAME);

	/*
	 * We don't allow a dentry to be silly-renamed twice.
	 */
	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
		goto out;

	fileid = NFS_FILEID(dentry->d_inode);

	/* Return delegation in anticipation of the rename */
	NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode);

	sdentry = NULL;
	do {
		int slen;
		dput(sdentry);
		sillycounter++;
		slen = scnprintf(silly, sizeof(silly),
				SILLYNAME_PREFIX "%0*llx%0*x",
				SILLYNAME_FILEID_LEN, fileid,
				SILLYNAME_COUNTER_LEN, sillycounter);

		dfprintk(VFS, "NFS: trying to rename %s to %s\n",
				dentry->d_name.name, silly);

		sdentry = lookup_one_len(silly, dentry->d_parent, slen);
		/*
		 * N.B. Better to return EBUSY here ... it could be
		 * dangerous to delete the file while it's in use.
		 */
		if (IS_ERR(sdentry))
			goto out;
	} while (sdentry->d_inode != NULL); /* need negative lookup */

	/* queue unlink first. Can't do this from rpc_release as it
	 * has to allocate memory
	 */
	error = nfs_async_unlink(dir, dentry);
	if (error)
		goto out_dput;

	/* populate unlinkdata with the right dname */
	error = nfs_copy_dname(sdentry,
				(struct nfs_unlinkdata *)dentry->d_fsdata);
	if (error) {
		nfs_cancel_async_unlink(dentry);
		goto out_dput;
	}

	/* run the rename task, undo unlink if it fails */
	task = nfs_async_rename(dir, dir, dentry, sdentry);
	if (IS_ERR(task)) {
		error = -EBUSY;
		nfs_cancel_async_unlink(dentry);
		goto out_dput;
	}

	/* wait for the RPC task to complete, unless a SIGKILL intervenes */
	error = rpc_wait_for_completion_task(task);
	if (error == 0)
		error = task->tk_status;
	switch (error) {
	case 0:
		/* The rename succeeded */
		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
		d_move(dentry, sdentry);
		break;
	case -ERESTARTSYS:
		/* The result of the rename is unknown. Play it safe by
		 * forcing a new lookup */
		d_drop(dentry);
		d_drop(sdentry);
	}
	rpc_put_task(task);
out_dput:
	dput(sdentry);
out:
	return error;
}
Пример #5
0
/*
 * Find an eligible tree to time-out
 * A tree is eligible if :-
 *  - it is unused by any user process
 *  - it has been unused for exp_timeout time
 */
struct dentry *autofs4_expire_indirect(struct super_block *sb,
				       struct vfsmount *mnt,
				       struct autofs_sb_info *sbi,
				       int how)
{
	unsigned long timeout;
	struct dentry *root = sb->s_root;
	struct dentry *dentry;
	struct dentry *expired = NULL;
	int do_now = how & AUTOFS_EXP_IMMEDIATE;
	int exp_leaves = how & AUTOFS_EXP_LEAVES;
	struct autofs_info *ino;
	unsigned int ino_count;

	if (!root)
		return NULL;

	now = jiffies;
	timeout = sbi->exp_timeout;

	dentry = NULL;
	while ((dentry = get_next_positive_subdir(dentry, root))) {
		spin_lock(&sbi->fs_lock);
		ino = autofs4_dentry_ino(dentry);
		/* No point expiring a pending mount */
		if (ino->flags & AUTOFS_INF_PENDING)
			goto next;

		/*
		 * Case 1: (i) indirect mount or top level pseudo direct mount
		 *	   (autofs-4.1).
		 *	   (ii) indirect mount with offset mount, check the "/"
		 *	   offset (autofs-5.0+).
		 */
		if (d_mountpoint(dentry)) {
			DPRINTK("checking mountpoint %p %.*s",
				dentry, (int)dentry->d_name.len, dentry->d_name.name);

			/* Can we umount this guy */
			if (autofs4_mount_busy(mnt, dentry))
				goto next;

			/* Can we expire this guy */
			if (autofs4_can_expire(dentry, timeout, do_now)) {
				expired = dentry;
				goto found;
			}
			goto next;
		}

		if (simple_empty(dentry))
			goto next;

		/* Case 2: tree mount, expire iff entire tree is not busy */
		if (!exp_leaves) {
			/* Path walk currently on this dentry? */
			ino_count = atomic_read(&ino->count) + 1;
			if (d_count(dentry) > ino_count)
				goto next;

			if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
				expired = dentry;
				goto found;
			}
		/*
		 * Case 3: pseudo direct mount, expire individual leaves
		 *	   (autofs-4.1).
		 */
		} else {
			/* Path walk currently on this dentry? */
			ino_count = atomic_read(&ino->count) + 1;
			if (d_count(dentry) > ino_count)
				goto next;

			expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
			if (expired) {
				dput(dentry);
				goto found;
			}
		}
next:
		spin_unlock(&sbi->fs_lock);
	}
	return NULL;

found:
	DPRINTK("returning %p %.*s",
		expired, (int)expired->d_name.len, expired->d_name.name);
	ino = autofs4_dentry_ino(expired);
	ino->flags |= AUTOFS_INF_EXPIRING;
	init_completion(&ino->expire_complete);
	spin_unlock(&sbi->fs_lock);
	spin_lock(&sbi->lookup_lock);
	spin_lock(&expired->d_parent->d_lock);
	spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
	list_move(&expired->d_parent->d_subdirs, &expired->d_child);
	spin_unlock(&expired->d_lock);
	spin_unlock(&expired->d_parent->d_lock);
	spin_unlock(&sbi->lookup_lock);
	return expired;
}
Пример #6
0
/* Check a directory tree of mount points for busyness
 * The tree is not busy iff no mountpoints are busy
 */
static int autofs4_tree_busy(struct vfsmount *mnt,
	       		     struct dentry *top,
			     unsigned long timeout,
			     int do_now)
{
	struct autofs_info *top_ino = autofs4_dentry_ino(top);
	struct dentry *p;

	DPRINTK("top %p %.*s",
		top, (int)top->d_name.len, top->d_name.name);

	/* Negative dentry - give up */
	if (!simple_positive(top))
		return 1;

	p = NULL;
	while ((p = get_next_positive_dentry(p, top))) {
		DPRINTK("dentry %p %.*s",
			p, (int) p->d_name.len, p->d_name.name);

		/*
		 * Is someone visiting anywhere in the subtree ?
		 * If there's no mount we need to check the usage
		 * count for the autofs dentry.
		 * If the fs is busy update the expiry counter.
		 */
		if (d_mountpoint(p)) {
			if (autofs4_mount_busy(mnt, p)) {
				top_ino->last_used = jiffies;
				dput(p);
				return 1;
			}
		} else {
			struct autofs_info *ino = autofs4_dentry_ino(p);
			unsigned int ino_count = atomic_read(&ino->count);

			/*
			 * Clean stale dentries below that have not been
			 * invalidated after a mount fail during lookup
			 */
			d_invalidate(p);

			/* allow for dget above and top is already dgot */
			if (p == top)
				ino_count += 2;
			else
				ino_count++;

			if (d_count(p) > ino_count) {
				top_ino->last_used = jiffies;
				dput(p);
				return 1;
			}
		}
	}

	/* Timeout of a tree mount is ultimately determined by its top dentry */
	if (!autofs4_can_expire(top, timeout, do_now))
		return 1;

	return 0;
}
Пример #7
0
/**
 * nilfs_tree_is_busy() - try to shrink dentries of a checkpoint
 * @root_dentry: root dentry of the tree to be shrunk
 *
 * This function returns true if the tree was in-use.
 */
static bool nilfs_tree_is_busy(struct dentry *root_dentry)
{
	shrink_dcache_parent(root_dentry);
	return d_count(root_dentry) > 1;
}
Пример #8
0
void printZlibInfo(const std::vector<unsigned char>& in, const Options& options)
{
  if(!options.zlib_info && !options.zlib_blocks) return;

  std::vector<lodepng::ZlibBlockInfo> zlibinfo;
  lodepng::extractZlibInfo(zlibinfo, in);

  if(options.zlib_info)
  {
    //std::cout << "Zlib info: " << std::endl;
    size_t compressed = 0;
    size_t uncompressed = 0;
    std::vector<size_t> boundaries_compressed;
    std::vector<size_t> boundaries_uncompressed;
    for(size_t i = 0; i < zlibinfo.size(); i++)
    {
      compressed += zlibinfo[i].compressedbits / 8;
      uncompressed += zlibinfo[i].uncompressedbytes;
      boundaries_compressed.push_back(compressed);
      boundaries_uncompressed.push_back(uncompressed);
    }

    std::cout << "Compressed size: " << compressed << std::endl;
    std::cout << "Uncompressed size: " << uncompressed << std::endl;
    std::cout << "Amount of zlib blocks: " << zlibinfo.size() << std::endl;
    if(zlibinfo.size() > 1)
    {
      std::cout << "Block sizes (uncompressed): ";
      for(size_t i = 0; i < zlibinfo.size(); i++)
          std::cout << zlibinfo[i].uncompressedbytes << " ";
      std::cout << std::endl;
      std::cout << "Block sizes (compressed): ";
      for(size_t i = 0; i < zlibinfo.size(); i++)
          std::cout << (zlibinfo[i].compressedbits / 8) << " ";
      std::cout << std::endl;
      std::cout << "Block boundaries (uncompressed): ";
      for(size_t i = 0; i + 1 < boundaries_uncompressed.size(); i++)
          std::cout << boundaries_uncompressed[i] << " ";
      std::cout << std::endl;
      std::cout << "Block boundaries (compressed): ";
      for(size_t i = 0; i + 1 < boundaries_compressed.size(); i++)
          std::cout << boundaries_compressed[i] << " ";
      std::cout << std::endl;
    }
  }

  if(options.zlib_blocks)
  {
    for(size_t i = 0; i < zlibinfo.size(); i++)
    {
      const lodepng::ZlibBlockInfo& info = zlibinfo[i];

      std::cout << "Zlib block " << i << ":" << std::endl;
      std::cout << " block type: " << info.btype << std::endl;

      size_t compressedsize = info.compressedbits / 8;
      size_t uncompressedsize = info.uncompressedbytes;
      std::cout << " block compressed: " << compressedsize << " (" << compressedsize / 1024 << "K) (" << info.compressedbits << " bits)" << std::endl;
      std::cout << " block uncompressed: " << uncompressedsize << " (" << uncompressedsize / 1024 << "K)" << std::endl;

      if(info.btype > 2)
      {
        std::cout << "Error: Invalid Block Type" << std::endl;
        return;
      }

      if(info.btype == 2)
      {
        std::cout << " encoded trees size: " << info.treebits / 8 << " (" << info.treebits << " bits)" << std::endl;
        std::cout << " HLIT: " << info.hlit << std::endl;
        std::cout << " HDIST: " << info.hdist << std::endl;
        std::cout << " HCLEN: " << info.hclen << std::endl;
        std::cout << std::hex;
        std::cout << " code length code lengths: "; for(size_t j = 0; j < 19; j++) std::cout << info.clcl[j]; std::cout << std::endl;
        if(!options.use_hex) std::cout << std::dec;
        if(options.zlib_full)
        {
          for(size_t j = 0; j < info.treecodes.size(); j++)
          {
            int code = info.treecodes[j];
            if(code < 17)
            {
               std::cout << " tree: " << code << std::endl;
            }
            else
            {
              j++;
              std::cout << " tree: " << code << " rep: " << info.treecodes[j] << std::endl;
            }
            
          }
        }

        std::cout << std::hex;
        std::cout << " lit code lengths 0-127  : "; for(size_t j = 0; j < 128; j++) std::cout << info.litlenlengths[j]; std::cout << std::endl;
        std::cout << " lit code lengths 128-255: "; for(size_t j = 128; j < 256; j++) std::cout << info.litlenlengths[j]; std::cout << std::endl;
        std::cout << " end code length         : "; std::cout << info.litlenlengths[256]; std::cout << std::endl;
        std::cout << " len code lengths        : "; for(size_t j = 257; j < 288; j++) std::cout << info.litlenlengths[j]; std::cout << std::endl;
        std::cout << " dist code lengths       : "; for(size_t j = 0; j < 32; j++) std::cout << info.distlengths[j]; std::cout << std::endl;
        if(!options.use_hex) std::cout << std::dec;
      }
      

      if(info.btype != 0)
      {
        std::cout << " code counts: lit: " << info.numlit << ", len/dist: " << info.numlen << ", total: " << (info.numlit + info.numlen + 1) << ", with dists: " << (info.numlit + 2 * info.numlen + 1) << std::endl;

        if(options.zlib_full)
        {
          for(size_t j = 0; j < info.lz77_lcode.size(); j++)
          {
            int symbol = info.lz77_lcode[j];
            if(symbol == 256)
            {
              std::cout << " end" << std::endl;
            }
            else if(symbol < 256)
            {
              std::cout << " lit: " << symbol << std::endl;
            }
            else
            {
              std::cout << " len: " << info.lz77_lvalue[j] << ", dist: " << info.lz77_dvalue[j] << std::endl;
            }
          }
        }

        if(options.zlib_counts)
        {
          std::vector<size_t> ll_count(288, 0);
          std::vector<size_t> d_count(32, 0);
          for(size_t j = 0; j < info.lz77_lcode.size(); j++)
          {
            int symbol = info.lz77_lcode[j];
            if(symbol <= 256)
            {
              ll_count[symbol]++;
            }
            else
            {
              ll_count[symbol]++;
              d_count[info.lz77_dcode[j]]++;
            }
          }
          std::cout << " lit code 0-63 counts   : "; for(size_t j = 0; j < 64; j++) std::cout << ll_count[j] << " "; std::cout << std::endl;
          std::cout << " lit code 64-127 counts : "; for(size_t j = 64; j < 128; j++) std::cout << ll_count[j] << " "; std::cout << std::endl;
          std::cout << " lit code 128-191 counts: "; for(size_t j = 128; j < 192; j++) std::cout << ll_count[j] << " "; std::cout << std::endl;
          std::cout << " lit code 192-255 counts: "; for(size_t j = 192; j < 256; j++) std::cout << ll_count[j] << " "; std::cout << std::endl;
          std::cout << " end code count         : "; std::cout << ll_count[256] << " "; std::cout << std::endl;
          std::cout << " len code counts        : "; for(size_t j = 257; j < 288; j++) std::cout << ll_count[j] << " "; std::cout << std::endl;
          std::cout << " dist code counts       : "; for(size_t j = 0; j < 32; j++) std::cout << d_count[j] << " "; std::cout << std::endl;
        }
      }
    }
  }
}