Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8cbdd85b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-v4.8' of git://github.com/martinbrandenburg/linux

Pull orangefs update from Martin Brandenburg:
 "Kernel side caching and executable bugfix

  This allows OrangeFS to utilize the dcache and adds an in kernel
  attribute cache.  We previously used the user side client for this
  purpose.

  We see a modest performance increase on small file operations.  For
  example, without the cache, compiling coreutils takes about 17
  minutes.  With the patch and a 50 millisecond timeout for
  dcache_timeout_msecs and getattr_timeout_msecs (the default),
  compiling coreutils takes about 6 minutes 20 seconds.  On the same
  hardware, compiling coreutils on an xfs filesystem takes 90 seconds.
  We see similar improvements with mdtest and a test involving writing,
  reading, and deleting a large number of small files.

  Interested parties can review more data at the following URL.

    https://docs.google.com/spreadsheets/d/1v4aUeppKexIbRMz_Yn9k4eaM3uy2KCaPoe_93YKWOtA/pubhtml

  The eventual goal of this is to allow getdents to turn into a
  readdirplus to the OrangeFS server.  The cache will be filled then,
  which should provide a performance benefit to the common case of
  readdir followed by getattr on each entry (i.e.  ls -l).

  This also fixes a bug.  When orangefs_inode_permission was added, it
  did not collect i_size from the OrangeFS server, since this presses an
  unnecessary load on the OrangeFS server.  However, it left a case
  where i_size is never initialized.  Then running an executable could
  fail.

  With this patch, size is always collected to be inserted into the
  cache.  Thus the bug disappears.  If this patch is not accepted during
  this merge window, we will send a one-line band-aid for this bug
  instead"

* tag 'for-linus-v4.8' of git://github.com/martinbrandenburg/linux:
  Orangefs: update orangefs.txt
  orangefs: Account for jiffies wraparound.
  orangefs: Change default dcache and getattr timeout to 50 msec.
  orangefs: Allow dcache and getattr cache time to be configured.
  orangefs: Cache getattr results.
  orangefs: Use d_time to avoid excessive lookups
parents 72b5ac54 302f0493
Loading
Loading
Loading
Loading
+46 −4
Original line number Diff line number Diff line
@@ -403,4 +403,46 @@ Readdir responses initialize the fifth element io_array like this:
                        from out_downcall member of global variable
                        vfs_request

Orangefs exploits the dcache in order to avoid sending redundant
requests to userspace. We keep object inode attributes up-to-date with
orangefs_inode_getattr. Orangefs_inode_getattr uses two arguments to
help it decide whether or not to update an inode: "new" and "bypass".
Orangefs keeps private data in an object's inode that includes a short
timeout value, getattr_time, which allows any iteration of
orangefs_inode_getattr to know how long it has been since the inode was
updated. When the object is not new (new == 0) and the bypass flag is not
set (bypass == 0) orangefs_inode_getattr returns without updating the inode
if getattr_time has not timed out. Getattr_time is updated each time the
inode is updated.

Creation of a new object (file, dir, sym-link) includes the evaluation of
its pathname, resulting in a negative directory entry for the object.
A new inode is allocated and associated with the dentry, turning it from
a negative dentry into a "productive full member of society". Orangefs
obtains the new inode from Linux with new_inode() and associates
the inode with the dentry by sending the pair back to Linux with
d_instantiate().

The evaluation of a pathname for an object resolves to its corresponding
dentry. If there is no corresponding dentry, one is created for it in
the dcache. Whenever a dentry is modified or verified Orangefs stores a
short timeout value in the dentry's d_time, and the dentry will be trusted
for that amount of time. Orangefs is a network filesystem, and objects
can potentially change out-of-band with any particular Orangefs kernel module
instance, so trusting a dentry is risky. The alternative to trusting
dentries is to always obtain the needed information from userspace - at
least a trip to the client-core, maybe to the servers. Obtaining information
from a dentry is cheap, obtaining it from userspace is relatively expensive,
hence the motivation to use the dentry when possible.

The timeout values d_time and getattr_time are jiffy based, and the
code is designed to avoid the jiffy-wrap problem:

"In general, if the clock may have wrapped around more than once, there
is no way to tell how much time has elapsed. However, if the times t1
and t2 are known to be fairly close, we can reliably compute the
difference in a way that takes into account the possibility that the
clock may have wrapped between times."

                      from course notes by instructor Andy Wang
+4 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ static int orangefs_revalidate_lookup(struct dentry *dentry)
		}
	}

	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
	ret = 1;
out_release_op:
	op_release(new_op);
@@ -94,6 +95,9 @@ static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
{
	int ret;

	if (time_before(jiffies, dentry->d_time))
		return 1;

	if (flags & LOOKUP_RCU)
		return -ECHILD;

+3 −3
Original line number Diff line number Diff line
@@ -262,7 +262,7 @@ int orangefs_getattr(struct vfsmount *mnt,
		     "orangefs_getattr: called on %s\n",
		     dentry->d_name.name);

	ret = orangefs_inode_getattr(inode, 0, 1);
	ret = orangefs_inode_getattr(inode, 0, 0);
	if (ret == 0) {
		generic_fillattr(inode, kstat);

@@ -384,7 +384,7 @@ struct inode *orangefs_iget(struct super_block *sb, struct orangefs_object_kref
	if (!inode || !(inode->i_state & I_NEW))
		return inode;

	error = orangefs_inode_getattr(inode, 1, 0);
	error = orangefs_inode_getattr(inode, 1, 1);
	if (error) {
		iget_failed(inode);
		return ERR_PTR(error);
@@ -429,7 +429,7 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
	orangefs_set_inode(inode, ref);
	inode->i_ino = hash;	/* needed for stat etc */

	error = orangefs_inode_getattr(inode, 1, 0);
	error = orangefs_inode_getattr(inode, 1, 1);
	if (error)
		goto out_iput;

+12 −0
Original line number Diff line number Diff line
@@ -72,6 +72,8 @@ static int orangefs_create(struct inode *dir,

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: dentry instantiated for %s\n",
@@ -181,6 +183,8 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
		goto out;
	}

	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;

	inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
	if (IS_ERR(inode)) {
		gossip_debug(GOSSIP_NAME_DEBUG,
@@ -189,6 +193,8 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
		goto out;
	}

	ORANGEFS_I(inode)->getattr_time = jiffies - 1;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s:%s:%d "
		     "Found good inode [%lu] with count [%d]\n",
@@ -316,6 +322,8 @@ static int orangefs_symlink(struct inode *dir,

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Inode (Symlink) %pU -> %s\n",
@@ -378,6 +386,8 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
	dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Inode (Directory) %pU -> %s\n",
@@ -408,6 +418,8 @@ static int orangefs_rename(struct inode *old_dir,
		     "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
		     old_dentry, new_dentry, d_count(new_dentry));

	ORANGEFS_I(new_dentry->d_parent->d_inode)->getattr_time = jiffies - 1;

	new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
	if (!new_op)
		return -EINVAL;
+5 −1
Original line number Diff line number Diff line
@@ -246,6 +246,8 @@ struct orangefs_inode_s {
	 * with this object
	 */
	unsigned long pinode_flags;

	unsigned long getattr_time;
};

#define P_ATIME_FLAG 0
@@ -527,7 +529,7 @@ int orangefs_inode_setxattr(struct inode *inode,
			 size_t size,
			 int flags);

int orangefs_inode_getattr(struct inode *inode, int new, int size);
int orangefs_inode_getattr(struct inode *inode, int new, int bypass);

int orangefs_inode_check_changed(struct inode *inode);

@@ -546,6 +548,8 @@ extern struct mutex request_mutex;
extern int debug;
extern int op_timeout_secs;
extern int slot_timeout_secs;
extern int dcache_timeout_msecs;
extern int getattr_timeout_msecs;
extern struct list_head orangefs_superblocks;
extern spinlock_t orangefs_superblocks_lock;
extern struct list_head orangefs_request_list;
Loading