4242 file rename event fires before the rename happens

illumos/illumos-gate@54207fd2e1
54207fd2e1

https://www.illumos.org/issues/4242
  From Joyent's OS-2557:
  So we're basically just doing a check here that after we got a 'rename' event
  for our file, the file has actually been moved out of the way.
  What I've seen in bh1-stage2 is that this happens as you'd expect for all zones
  but many times over the last week it's failed because when we do the fs.exists
  () check here, the file that we got the rename event for, still exists.
  I've confirmed what's happening using the following dtrace script:
  #!/usr/sbin/dtrace -s

  #pragma D option quiet
  #pragma D option bufsize=256k

  syscall::open:entry,
  syscall::open64:entry
  /copyinstr(arg0) == "/var/svc/provisioning" || (strlen(copyinstr(arg0)) == 69
  && substr(copyinstr(arg0), 48) == "/var/svc/provisioning")/
  {
      this->watching_open = 1;
      printf("%d zone %s process %s(%d) [%s] open(%s)\\n",
          timestamp,
          zonename,
          execname,
          pid,
          curpsinfo->pr_psargs,
          copyinstr(arg0));
  }

  syscall::open:return,
  syscall::open64:return
  /this->watching_open == 1/

Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Marcel Telka <marcel@telka.sk>
Approved by: Dan McDonald <danmcd@omniti.com>
Author: Jerry Jelinek <jerry.jelinek@joyent.com>
This commit is contained in:
Andriy Gapon 2017-04-14 18:19:48 +00:00
parent 9dfe195883
commit be49e7b29b
3 changed files with 62 additions and 7 deletions

View File

@ -2556,6 +2556,36 @@ vnevent_rmdir(vnode_t *vp, vnode_t *dvp, char *name, caller_context_t *ct)
(void) VOP_VNEVENT(vp, VE_RMDIR, dvp, name, ct);
}
void
vnevent_pre_rename_src(vnode_t *vp, vnode_t *dvp, char *name,
caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
(void) VOP_VNEVENT(vp, VE_PRE_RENAME_SRC, dvp, name, ct);
}
void
vnevent_pre_rename_dest(vnode_t *vp, vnode_t *dvp, char *name,
caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
(void) VOP_VNEVENT(vp, VE_PRE_RENAME_DEST, dvp, name, ct);
}
void
vnevent_pre_rename_dest_dir(vnode_t *vp, vnode_t *nvp, char *name,
caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
(void) VOP_VNEVENT(vp, VE_PRE_RENAME_DEST_DIR, nvp, name, ct);
}
void
vnevent_create(vnode_t *vp, caller_context_t *ct)
{

View File

@ -23,6 +23,7 @@
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2015 Joyent, Inc.
*/
/* Portions Copyright 2007 Jeremy Teo */
@ -3447,7 +3448,7 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
dmu_tx_t *tx;
zfs_zlock_t *zl;
int cmp, serr, terr;
int error = 0;
int error = 0, rm_err = 0;
int zflg = 0;
boolean_t waited = B_FALSE;
@ -3659,16 +3660,16 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
}
}
vnevent_rename_src(ZTOV(szp), sdvp, snm, ct);
vnevent_pre_rename_src(ZTOV(szp), sdvp, snm, ct);
if (tzp)
vnevent_rename_dest(ZTOV(tzp), tdvp, tnm, ct);
vnevent_pre_rename_dest(ZTOV(tzp), tdvp, tnm, ct);
/*
* notify the target directory if it is not the same
* as source directory.
*/
if (tdvp != sdvp) {
vnevent_rename_dest_dir(tdvp, ct);
vnevent_pre_rename_dest_dir(tdvp, ZTOV(szp), tnm, ct);
}
tx = dmu_tx_create(zfsvfs->z_os);
@ -3712,7 +3713,7 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
}
if (tzp) /* Attempt to remove the existing target */
error = zfs_link_destroy(tdl, tzp, tx, zflg, NULL);
error = rm_err = zfs_link_destroy(tdl, tzp, tx, zflg, NULL);
if (error == 0) {
error = zfs_link_create(tdl, szp, tx, ZRENAMING);
@ -3754,6 +3755,16 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
}
dmu_tx_commit(tx);
if (tzp && rm_err == 0)
vnevent_rename_dest(ZTOV(tzp), tdvp, tnm, ct);
if (error == 0) {
vnevent_rename_src(ZTOV(szp), sdvp, snm, ct);
/* notify the target dir if it is not the same as source dir */
if (tdvp != sdvp)
vnevent_rename_dest_dir(tdvp, ct);
}
out:
if (zl != NULL)
zfs_rename_unlock(&zl);

View File

@ -724,7 +724,12 @@ typedef enum symfollow symfollow_t;
typedef enum vcexcl vcexcl_t;
typedef enum create create_t;
/* Vnode Events - Used by VOP_VNEVENT */
/*
* Vnode Events - Used by VOP_VNEVENT
* The VE_PRE_RENAME_* events fire before the rename operation and are
* primarily used for specialized applications, such as NFSv4 delegation, which
* need to know about rename before it occurs.
*/
typedef enum vnevent {
VE_SUPPORT = 0, /* Query */
VE_RENAME_SRC = 1, /* Rename, with vnode as source */
@ -735,7 +740,10 @@ typedef enum vnevent {
VE_LINK = 6, /* Link with vnode's name as source */
VE_RENAME_DEST_DIR = 7, /* Rename with vnode as target dir */
VE_MOUNTEDOVER = 8, /* File or Filesystem got mounted over vnode */
VE_TRUNCATE = 9 /* Truncate */
VE_TRUNCATE = 9, /* Truncate */
VE_PRE_RENAME_SRC = 10, /* Pre-rename, with vnode as source */
VE_PRE_RENAME_DEST = 11, /* Pre-rename, with vnode as target/dest. */
VE_PRE_RENAME_DEST_DIR = 12 /* Pre-rename with vnode as target dir */
} vnevent_t;
/*
@ -1294,6 +1302,12 @@ void vnevent_rename_dest_dir(vnode_t *, caller_context_t *ct);
void vnevent_mountedover(vnode_t *, caller_context_t *);
void vnevent_truncate(vnode_t *, caller_context_t *);
int vnevent_support(vnode_t *, caller_context_t *);
void vnevent_pre_rename_src(vnode_t *, vnode_t *, char *,
caller_context_t *);
void vnevent_pre_rename_dest(vnode_t *, vnode_t *, char *,
caller_context_t *);
void vnevent_pre_rename_dest_dir(vnode_t *, vnode_t *, char *,
caller_context_t *);
/* Vnode specific data */
void vsd_create(uint_t *, void (*)(void *));