diff options
37 files changed, 1526 insertions, 40 deletions
diff --git a/api/examples/gfapi.py b/api/examples/gfapi.py index 8dfe2791d..8d9ed7329 100755 --- a/api/examples/gfapi.py +++ b/api/examples/gfapi.py @@ -100,6 +100,8 @@ class File(object):  	def fallocate (self, mode, offset, len):  		return api.glfs_fallocate(self.fd, mode, offset, len) +	def discard (self, offset, len): +		return api.glfs_discard(self.fd, offset, len)  class Dir(object): @@ -357,10 +359,13 @@ if __name__ == "__main__":                  fd = vol.creat(mypath,os.O_WRONLY|os.O_EXCL,0644)                  if not fd:                          return False, "creat error" -		rc = fd.fallocate(0, 0, 1024) +		rc = fd.fallocate(0, 0, 1024*1024)                  if rc != 0:                          return False, "fallocate error" -                return True, "fallocate worked" +		rc = fd.discard(4096, 4096) +		if rc != 0: +			return False, "discard error" +                return True, "fallocate/discard worked"          test_list = (                  test_create_write, diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c index 4bc0bb1b6..fbc9f4b49 100644 --- a/api/src/glfs-fops.c +++ b/api/src/glfs-fops.c @@ -2666,6 +2666,40 @@ out:  int +glfs_discard (struct glfs_fd *glfd, off_t offset, size_t len) +{ +	int              ret = -1; +	xlator_t        *subvol = NULL; +	fd_t		*fd = NULL; + +	__glfs_entry_fd (glfd); + +	subvol = glfs_active_subvol (glfd->fs); +	if (!subvol) { +		ret = -1; +		errno = EIO; +		goto out; +	} + +	fd = glfs_resolve_fd (glfd->fs, subvol, glfd); +	if (!fd) { +		ret = -1; +		errno = EBADFD; +		goto out; +	} + +	ret = syncop_discard (subvol, fd, offset, len); +out: +	if (fd) +		fd_unref(fd); + +	glfs_subvol_done (glfd->fs, subvol); + +	return ret; +} + + +int  glfs_chdir (struct glfs *fs, const char *path)  {  	int              ret = -1; diff --git a/api/src/glfs.h b/api/src/glfs.h index 3888a103e..700e10f17 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -450,6 +450,8 @@ int glfs_fremovexattr (glfs_fd_t *fd, const char *name);  int glfs_fallocate(glfs_fd_t *fd, int keep_size, off_t offset, size_t len); +int glfs_discard(glfs_fd_t *fd, off_t offset, size_t len); +  char *glfs_getcwd (glfs_t *fs, char *buf, size_t size);  int glfs_chdir (glfs_t *fs, const char *path); diff --git a/libglusterfs/src/call-stub.c b/libglusterfs/src/call-stub.c index 2bb993411..2f07a0074 100644 --- a/libglusterfs/src/call-stub.c +++ b/libglusterfs/src/call-stub.c @@ -2186,6 +2186,61 @@ out:  } +call_stub_t * +fop_discard_cbk_stub(call_frame_t *frame, fop_discard_cbk_t fn, +                     int32_t op_ret, int32_t op_errno, +                     struct iatt *statpre, struct iatt *statpost, +		     dict_t *xdata) +{ +        call_stub_t *stub = NULL; + +        GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + +        stub = stub_new (frame, 0, GF_FOP_DISCARD); +        GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + +        stub->fn_cbk.discard = fn; + +        stub->args_cbk.op_ret = op_ret; +        stub->args_cbk.op_errno = op_errno; + +        if (statpre) +                stub->args_cbk.prestat = *statpre; +        if (statpost) +                stub->args_cbk.poststat = *statpost; +        if (xdata) +                stub->args_cbk.xdata = dict_ref (xdata); +out: +        return stub; +} + +call_stub_t * +fop_discard_stub(call_frame_t *frame, fop_discard_t fn, fd_t *fd, +		 off_t offset, size_t len, dict_t *xdata) +{ +        call_stub_t *stub = NULL; + +        GF_VALIDATE_OR_GOTO ("call-stub", frame, out); +        GF_VALIDATE_OR_GOTO ("call-stub", fn, out); + +        stub = stub_new (frame, 1, GF_FOP_DISCARD); +        GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + +        stub->fn.discard = fn; + +        if (fd) +                stub->args.fd = fd_ref (fd); + +	stub->args.offset = offset; +	stub->args.size = len; + +        if (xdata) +                stub->args.xdata = dict_ref (xdata); +out: +        return stub; + +} +  static void  call_resume_wind (call_stub_t *stub)  { @@ -2408,6 +2463,11 @@ call_resume_wind (call_stub_t *stub)  				   stub->args.offset, stub->args.size,  				   stub->args.xdata);  		break; +	case GF_FOP_DISCARD: +		stub->fn.discard(stub->frame, stub->frame->this, +				 stub->args.fd, stub->args.offset, +				 stub->args.size, stub->args.xdata); +		break;          default:                  gf_log_callingfn ("call-stub", GF_LOG_ERROR,                                    "Invalid value of FOP (%d)", @@ -2606,6 +2666,10 @@ call_resume_unwind (call_stub_t *stub)  		STUB_UNWIND(stub, fallocate, &stub->args_cbk.prestat,  			    &stub->args_cbk.poststat, stub->args_cbk.xdata);  		break; +	case GF_FOP_DISCARD: +		STUB_UNWIND(stub, discard, &stub->args_cbk.prestat, +			    &stub->args_cbk.poststat, stub->args_cbk.xdata); +		break;          default:                  gf_log_callingfn ("call-stub", GF_LOG_ERROR,                                    "Invalid value of FOP (%d)", diff --git a/libglusterfs/src/call-stub.h b/libglusterfs/src/call-stub.h index d940fe6f1..f0872b121 100644 --- a/libglusterfs/src/call-stub.h +++ b/libglusterfs/src/call-stub.h @@ -70,6 +70,7 @@ typedef struct {  		fop_setattr_t setattr;  		fop_fsetattr_t fsetattr;  		fop_fallocate_t fallocate; +		fop_discard_t discard;  	} fn;  	union { @@ -115,6 +116,7 @@ typedef struct {  		fop_setattr_cbk_t setattr;  		fop_fsetattr_cbk_t fsetattr;  		fop_fallocate_cbk_t fallocate; +		fop_discard_cbk_t discard;  	} fn_cbk;  	struct { @@ -729,6 +731,20 @@ fop_fallocate_cbk_stub(call_frame_t *frame,                         struct iatt *statpre, struct iatt *statpost,                         dict_t *xdata); +call_stub_t * +fop_discard_stub(call_frame_t *frame, +		 fop_discard_t fn, +		 fd_t *fd, +		 off_t offset, +		 size_t len, dict_t *xdata); + +call_stub_t * +fop_discard_cbk_stub(call_frame_t *frame, +		     fop_discard_cbk_t fn, +                     int32_t op_ret, int32_t op_errno, +                     struct iatt *statpre, struct iatt *statpost, +                     dict_t *xdata); +  void call_resume (call_stub_t *stub);  void call_stub_destroy (call_stub_t *stub);  void call_unwind_error (call_stub_t *stub, int op_ret, int op_errno); diff --git a/libglusterfs/src/defaults.c b/libglusterfs/src/defaults.c index 32454a1e9..a3c8d97f1 100644 --- a/libglusterfs/src/defaults.c +++ b/libglusterfs/src/defaults.c @@ -464,6 +464,15 @@ default_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,  }  int32_t +default_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                    int32_t op_ret, int32_t op_errno, struct iatt *pre, +                    struct iatt *post, dict_t *xdata) +{ +	STACK_UNWIND_STRICT(discard, frame, op_ret, op_errno, pre, post, xdata); +	return 0; +} + +int32_t  default_getspec_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                       int32_t op_ret, int32_t op_errno, char *spec_data)  { @@ -881,6 +890,15 @@ default_fallocate_resume(call_frame_t *frame, xlator_t *this, fd_t *fd,          return 0;  } +int32_t +default_discard_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, +		       off_t offset, size_t len, dict_t *xdata) +{ +	STACK_WIND(frame, default_discard_cbk, FIRST_CHILD(this), +		   FIRST_CHILD(this)->fops->discard, fd, offset, len, +		   xdata); +        return 0; +}  /* FOPS */ @@ -1297,6 +1315,16 @@ default_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd,  }  int32_t +default_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, +		off_t offset, size_t len, dict_t *xdata) +{ +	STACK_WIND_TAIL(frame, FIRST_CHILD(this), +			FIRST_CHILD(this)->fops->discard, fd, offset, len, +			xdata); +	return 0; +} + +int32_t  default_forget (xlator_t *this, inode_t *inode)  {          gf_log_callingfn (this->name, GF_LOG_WARNING, "xlator does not " diff --git a/libglusterfs/src/defaults.h b/libglusterfs/src/defaults.h index bc2f6429b..f3cbb3a4b 100644 --- a/libglusterfs/src/defaults.h +++ b/libglusterfs/src/defaults.h @@ -249,6 +249,12 @@ int32_t default_fallocate(call_frame_t *frame,  			  int32_t keep_size, off_t offset,  			  size_t len, dict_t *xdata); +int32_t default_discard(call_frame_t *frame, +			xlator_t *this, +			fd_t *fd, +			off_t offset, +			size_t len, dict_t *xdata); +  /* Resume */  int32_t default_getspec_resume (call_frame_t *frame,                                  xlator_t *this, @@ -465,6 +471,11 @@ int32_t default_fallocate_resume(call_frame_t *frame,  				 int32_t keep_size, off_t offset,  				 size_t len, dict_t *xdata); +int32_t default_discard_resume(call_frame_t *frame, +			       xlator_t *this, +			       fd_t *fd, +			       off_t offset, +			       size_t len, dict_t *xdata);  /* _cbk */ @@ -680,6 +691,9 @@ int32_t default_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,  			      int32_t op_ret, int32_t op_errno, struct iatt *pre,  			      struct iatt *post, dict_t *xdata); +int32_t default_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +			    int32_t op_ret, int32_t op_errno, struct iatt *pre, +			    struct iatt *post, dict_t *xdata);  int32_t  default_getspec_cbk (call_frame_t *frame, void *cookie, xlator_t *this, diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c index ba5075b2e..072b1d523 100644 --- a/libglusterfs/src/globals.c +++ b/libglusterfs/src/globals.c @@ -68,6 +68,7 @@ const char *gf_fop_list[GF_FOP_MAXVALUE] = {          [GF_FOP_RELEASEDIR]  = "RELEASEDIR",          [GF_FOP_FREMOVEXATTR]= "FREMOVEXATTR",  	[GF_FOP_FALLOCATE]   = "FALLOCATE", +	[GF_FOP_DISCARD]     = "DISCARD",  };  /* THIS */ diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index 013cdfffa..c2fbf5ac4 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -198,6 +198,7 @@ typedef enum {          GF_FOP_GETSPEC,          GF_FOP_FREMOVEXATTR,  	GF_FOP_FALLOCATE, +	GF_FOP_DISCARD,          GF_FOP_MAXVALUE,  } glusterfs_fop_t; diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c index f57e8da5a..9cceaf55c 100644 --- a/libglusterfs/src/syncop.c +++ b/libglusterfs/src/syncop.c @@ -1948,6 +1948,36 @@ syncop_fallocate(xlator_t *subvol, fd_t *fd, int32_t keep_size, off_t offset,  int +syncop_discard_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                    int op_ret, int op_errno, struct iatt *prebuf, +                    struct iatt *postbuf, dict_t *xdata) +{ +	struct syncargs *args = NULL; + +        args = cookie; + +        args->op_ret   = op_ret; +        args->op_errno = op_errno; + +        __wake (args); + +	return 0; +} + +int +syncop_discard(xlator_t *subvol, fd_t *fd, off_t offset, size_t len) +{ +        struct syncargs args = {0, }; + +        SYNCOP (subvol, (&args), syncop_discard_cbk, subvol->fops->discard, +                fd, offset, len, NULL); + +        errno = args.op_errno; +        return args.op_ret; +} + + +int  syncop_lk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  	       int op_ret, int op_errno, struct gf_flock *flock,  	       dict_t *xdata) diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h index 59e62ad14..43e71c4f6 100644 --- a/libglusterfs/src/syncop.h +++ b/libglusterfs/src/syncop.h @@ -335,6 +335,7 @@ int syncop_fsyncdir (xlator_t *subvol, fd_t *fd, int datasync);  int syncop_access (xlator_t *subvol, loc_t *loc, int32_t mask);  int syncop_fallocate(xlator_t *subvol, fd_t *fd, int32_t keep_size, off_t offset,  		     size_t len); +int syncop_discard(xlator_t *subvol, fd_t *fd, off_t offset, size_t len);  int syncop_rename (xlator_t *subvol, loc_t *oldloc, loc_t *newloc); diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index 1926240e8..b1c090c1e 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -80,6 +80,7 @@ fill_defaults (xlator_t *xl)          SET_DEFAULT_FOP (setattr);          SET_DEFAULT_FOP (fsetattr);  	SET_DEFAULT_FOP (fallocate); +	SET_DEFAULT_FOP (discard);          SET_DEFAULT_FOP (getspec); diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h index ace73f2ed..817eaddec 100644 --- a/libglusterfs/src/xlator.h +++ b/libglusterfs/src/xlator.h @@ -425,6 +425,14 @@ typedef int32_t (*fop_fallocate_cbk_t) (call_frame_t *frame,                                          struct iatt *preop_stbuf,                                          struct iatt *postop_stbuf, dict_t *xdata); +typedef int32_t (*fop_discard_cbk_t) (call_frame_t *frame, +                                      void *cookie, +                                      xlator_t *this, +                                      int32_t op_ret, +                                      int32_t op_errno, +                                      struct iatt *preop_stbuf, +                                      struct iatt *postop_stbuf, dict_t *xdata); +  typedef int32_t (*fop_lookup_t) (call_frame_t *frame,                                   xlator_t *this,                                   loc_t *loc, @@ -650,6 +658,13 @@ typedef int32_t (*fop_fallocate_t) (call_frame_t *frame,  				    size_t len,                                      dict_t *xdata); +typedef int32_t (*fop_discard_t) (call_frame_t *frame, +                                  xlator_t *this, +                                  fd_t *fd, +				  off_t offset, +				  size_t len, +                                  dict_t *xdata); +  struct xlator_fops {          fop_lookup_t         lookup;          fop_stat_t           stat; @@ -694,6 +709,7 @@ struct xlator_fops {          fop_fsetattr_t       fsetattr;          fop_getspec_t        getspec;  	fop_fallocate_t	     fallocate; +	fop_discard_t	     discard;          /* these entries are used for a typechecking hack in STACK_WIND _only_ */          fop_lookup_cbk_t         lookup_cbk; @@ -739,6 +755,7 @@ struct xlator_fops {          fop_fsetattr_cbk_t       fsetattr_cbk;          fop_getspec_cbk_t        getspec_cbk;  	fop_fallocate_cbk_t	 fallocate_cbk; +	fop_discard_cbk_t	 discard_cbk;  };  typedef int32_t (*cbk_forget_t) (xlator_t *this, diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 214e84009..0457140dd 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -54,6 +54,7 @@ enum gf_fop_procnum {          GFS3_OP_FSETATTR,          GFS3_OP_READDIRP,  	GFS3_OP_FALLOCATE, +	GFS3_OP_DISCARD,          GFS3_OP_RELEASE,          GFS3_OP_RELEASEDIR,          GFS3_OP_FREMOVEXATTR, diff --git a/rpc/xdr/src/glusterfs3-xdr.c b/rpc/xdr/src/glusterfs3-xdr.c index 2ce0b84ed..4e9791b20 100644 --- a/rpc/xdr/src/glusterfs3-xdr.c +++ b/rpc/xdr/src/glusterfs3-xdr.c @@ -1547,6 +1547,44 @@ xdr_gfs3_fallocate_rsp (XDR *xdrs, gfs3_fallocate_rsp *objp)  }  bool_t +xdr_gfs3_discard_req (XDR *xdrs, gfs3_discard_req *objp) +{ +	register int32_t *buf; +        buf = NULL; + +	 if (!xdr_opaque (xdrs, objp->gfid, 16)) +		 return FALSE; +	 if (!xdr_quad_t (xdrs, &objp->fd)) +		 return FALSE; +	 if (!xdr_u_quad_t (xdrs, &objp->offset)) +		 return FALSE; +	 if (!xdr_u_quad_t (xdrs, &objp->size)) +		 return FALSE; +	 if (!xdr_bytes (xdrs, (char **)&objp->xdata.xdata_val, (u_int *) &objp->xdata.xdata_len, ~0)) +		 return FALSE; +	return TRUE; +} + +bool_t +xdr_gfs3_discard_rsp (XDR *xdrs, gfs3_discard_rsp *objp) +{ +	register int32_t *buf; +        buf = NULL; + +	 if (!xdr_int (xdrs, &objp->op_ret)) +		 return FALSE; +	 if (!xdr_int (xdrs, &objp->op_errno)) +		 return FALSE; +	 if (!xdr_gf_iatt (xdrs, &objp->statpre)) +		 return FALSE; +	 if (!xdr_gf_iatt (xdrs, &objp->statpost)) +		 return FALSE; +	 if (!xdr_bytes (xdrs, (char **)&objp->xdata.xdata_val, (u_int *) &objp->xdata.xdata_len, ~0)) +		 return FALSE; +	return TRUE; +} + +bool_t  xdr_gfs3_rchecksum_req (XDR *xdrs, gfs3_rchecksum_req *objp)  {  	register int32_t *buf; diff --git a/rpc/xdr/src/glusterfs3-xdr.h b/rpc/xdr/src/glusterfs3-xdr.h index 2f9ba4b45..9e5d2e67b 100644 --- a/rpc/xdr/src/glusterfs3-xdr.h +++ b/rpc/xdr/src/glusterfs3-xdr.h @@ -912,6 +912,30 @@ struct gfs3_fallocate_rsp {  };  typedef struct gfs3_fallocate_rsp gfs3_fallocate_rsp; +struct gfs3_discard_req { +	char gfid[16]; +	quad_t fd; +	u_quad_t offset; +	u_quad_t size; +	struct { +		u_int xdata_len; +		char *xdata_val; +	} xdata; +}; +typedef struct gfs3_discard_req gfs3_discard_req; + +struct gfs3_discard_rsp { +	int op_ret; +	int op_errno; +	struct gf_iatt statpre; +	struct gf_iatt statpost; +	struct { +		u_int xdata_len; +		char *xdata_val; +	} xdata; +}; +typedef struct gfs3_discard_rsp gfs3_discard_rsp; +  struct gfs3_rchecksum_req {  	quad_t fd;  	u_quad_t offset; @@ -1209,6 +1233,8 @@ extern  bool_t xdr_gfs3_fsetattr_req (XDR *, gfs3_fsetattr_req*);  extern  bool_t xdr_gfs3_fsetattr_rsp (XDR *, gfs3_fsetattr_rsp*);  extern  bool_t xdr_gfs3_fallocate_req (XDR *, gfs3_fallocate_req*);  extern  bool_t xdr_gfs3_fallocate_rsp (XDR *, gfs3_fallocate_rsp*); +extern  bool_t xdr_gfs3_discard_req (XDR *, gfs3_discard_req*); +extern  bool_t xdr_gfs3_discard_rsp (XDR *, gfs3_discard_rsp*);  extern  bool_t xdr_gfs3_rchecksum_req (XDR *, gfs3_rchecksum_req*);  extern  bool_t xdr_gfs3_rchecksum_rsp (XDR *, gfs3_rchecksum_rsp*);  extern  bool_t xdr_gf_setvolume_req (XDR *, gf_setvolume_req*); @@ -1305,6 +1331,8 @@ extern bool_t xdr_gfs3_fsetattr_req ();  extern bool_t xdr_gfs3_fsetattr_rsp ();  extern bool_t xdr_gfs3_fallocate_req ();  extern bool_t xdr_gfs3_fallocate_rsp (); +extern bool_t xdr_gfs3_discard_req (); +extern bool_t xdr_gfs3_discard_rsp ();  extern bool_t xdr_gfs3_rchecksum_req ();  extern bool_t xdr_gfs3_rchecksum_rsp ();  extern bool_t xdr_gf_setvolume_req (); diff --git a/rpc/xdr/src/glusterfs3-xdr.x b/rpc/xdr/src/glusterfs3-xdr.x index 7fad58336..e2b086b1d 100644 --- a/rpc/xdr/src/glusterfs3-xdr.x +++ b/rpc/xdr/src/glusterfs3-xdr.x @@ -583,6 +583,22 @@ struct gfs3_fstat_req {          opaque   xdata<>; /* Extra data */  }  ; + struct gfs3_discard_req { +	opaque		gfid[16]; +        hyper		fd; +	unsigned hyper	offset; +	unsigned hyper	size; +        opaque   xdata<>; /* Extra data */ +}  ; + + struct gfs3_discard_rsp { +        int    op_ret; +        int    op_errno; +        struct gf_iatt statpre; +        struct gf_iatt statpost; +        opaque   xdata<>; /* Extra data */ +}  ; +   struct gfs3_rchecksum_req {          hyper   fd;          unsigned hyper  offset; diff --git a/tests/bugs/bug-963678.t b/tests/bugs/bug-963678.t new file mode 100644 index 000000000..14d566579 --- /dev/null +++ b/tests/bugs/bug-963678.t @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Bug 963678 - Test discard functionality +# +# Test that basic discard (hole punch) functionality works via the fallocate +# command line tool. Hole punch deallocates a region of a file, creating a hole +# and a zero-filled data region. We verify that hole punch works, frees blocks +# and that subsequent reads do not read stale data (caches are invalidated). +# +# NOTE: fuse fallocate is known to be broken with regard to cache invalidation +# 	up to 3.9.0 kernels. Therefore, FOPEN_KEEP_CACHE is not used in this +#	test (opens will invalidate the fuse cache). +### + +. $(dirname $0)/../include.rc +. $(dirname $0)/../fallocate.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2} +TEST $CLI volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 + +# check for fallocate and hole punch support +require_fallocate -l 1m $M0/file +require_fallocate -p -l 512k $M0/file && rm -f $M0/file + +# allocate some blocks, punch a hole and verify block allocation +TEST fallocate -l 1m $M0/file +blksz=`stat --printf=%B $M0/file` +nblks=`stat --printf=%b $M0/file` +TEST [ $(($blksz * $nblks)) -ge 1048576 ] +TEST fallocate -p -o 512k -l 128k $M0/file + +nblks=`stat --printf=%b $M0/file` +# allow some room for xattr blocks +TEST [ $(($blksz * $nblks)) -lt $((917504 + 16384)) ] +TEST unlink $M0/file + +# write some data, punch a hole and verify the file content changes +TEST dd if=/dev/urandom of=$M0/file bs=1M count=1 +TEST cp $M0/file $M0/file.copy.pre +TEST fallocate -p -o 512k -l 128k $M0/file +TEST cp $M0/file $M0/file.copy.post +TEST ! cmp $M0/file.copy.pre $M0/file.copy.post +TEST unlink $M0/file + +TEST umount $M0 + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c index 830ecd993..20513d380 100644 --- a/xlators/cluster/afr/src/afr-common.c +++ b/xlators/cluster/afr/src/afr-common.c @@ -3065,6 +3065,247 @@ out:  /* }}} */ +/* {{{ discard */ + +static int +afr_discard_unwind (call_frame_t *frame, xlator_t *this) +{ +        afr_local_t *   local = NULL; +        call_frame_t   *main_frame = NULL; + +        local = frame->local; + +        LOCK (&frame->lock); +        { +                if (local->transaction.main_frame) +                        main_frame = local->transaction.main_frame; +                local->transaction.main_frame = NULL; +        } +        UNLOCK (&frame->lock); + +        if (main_frame) { +                AFR_STACK_UNWIND (discard, main_frame, local->op_ret, +                                  local->op_errno, +                                  &local->cont.discard.prebuf, +                                  &local->cont.discard.postbuf, +                                  NULL); +        } +        return 0; +} + +static int +afr_discard_wind_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                     int32_t op_ret, int32_t op_errno, struct iatt *prebuf, +                     struct iatt *postbuf, dict_t *xdata) +{ +        afr_local_t *   local = NULL; +        afr_private_t * priv  = NULL; +        int child_index = (long) cookie; +        int call_count  = -1; +        int need_unwind = 0; +        int read_child  = 0; + +        local = frame->local; +        priv  = this->private; + +        read_child = afr_inode_get_read_ctx (this, local->fd->inode, NULL); + +        LOCK (&frame->lock); +        { +                if (child_index == read_child) { +                        local->read_child_returned = _gf_true; +                } + +                if (afr_fop_failed (op_ret, op_errno)) +                        afr_transaction_fop_failed (frame, this, child_index); + +                if (op_ret != -1) { +                        if (local->success_count == 0) { +                                local->op_ret = op_ret; +                                local->cont.discard.prebuf  = *prebuf; +                                local->cont.discard.postbuf = *postbuf; +                        } + +                        if (child_index == read_child) { +                                local->cont.discard.prebuf  = *prebuf; +                                local->cont.discard.postbuf = *postbuf; +                        } + +                        local->success_count++; + +                        if ((local->success_count >= priv->wait_count) +                            && local->read_child_returned) { +                                need_unwind = 1; +                        } +                } +                local->op_errno = op_errno; +        } +        UNLOCK (&frame->lock); + +        if (need_unwind) +                local->transaction.unwind (frame, this); + +        call_count = afr_frame_return (frame); + +        if (call_count == 0) { +                local->transaction.resume (frame, this); +        } + +        return 0; +} + +static int +afr_discard_wind (call_frame_t *frame, xlator_t *this) +{ +        afr_local_t *local = NULL; +        afr_private_t *priv = NULL; +        int call_count = -1; +        int i = 0; + +        local = frame->local; +        priv = this->private; + +        call_count = afr_pre_op_done_children_count (local->transaction.pre_op, +                                                     priv->child_count); + +        if (call_count == 0) { +                local->transaction.resume (frame, this); +                return 0; +        } + +        local->call_count = call_count; + +        for (i = 0; i < priv->child_count; i++) { +                if (local->transaction.pre_op[i]) { +                        STACK_WIND_COOKIE (frame, afr_discard_wind_cbk, +                                           (void *) (long) i, +                                           priv->children[i], +                                           priv->children[i]->fops->discard, +                                           local->fd, +                                           local->cont.discard.offset, +					   local->cont.discard.len, +                                           NULL); + +                        if (!--call_count) +                                break; +                } +        } + +        return 0; +} + +static int +afr_discard_done (call_frame_t *frame, xlator_t *this) +{ +        afr_local_t *local = NULL; + +        local = frame->local; + +        local->transaction.unwind (frame, this); + +        AFR_STACK_DESTROY (frame); + +        return 0; +} + +static int +afr_do_discard(call_frame_t *frame, xlator_t *this) +{ +        call_frame_t * transaction_frame = NULL; +        afr_local_t *  local             = NULL; +        int op_ret   = -1; +        int op_errno = 0; + +        local = frame->local; + +        transaction_frame = copy_frame (frame); +        if (!transaction_frame) { +                goto out; +        } + +        transaction_frame->local = local; +        frame->local = NULL; + +        local->op = GF_FOP_DISCARD; + +        local->transaction.fop    = afr_discard_wind; +        local->transaction.done   = afr_discard_done; +        local->transaction.unwind = afr_discard_unwind; + +        local->transaction.main_frame = frame; + +        local->transaction.start   = local->cont.discard.offset; +        local->transaction.len     = 0; + +        op_ret = afr_transaction (transaction_frame, this, AFR_DATA_TRANSACTION); +        if (op_ret < 0) { +            op_errno = -op_ret; +            goto out; +        } + +        op_ret = 0; +out: +        if (op_ret < 0) { +                if (transaction_frame) +                        AFR_STACK_DESTROY (transaction_frame); +                AFR_STACK_UNWIND (discard, frame, op_ret, op_errno, NULL, +                                  NULL, NULL); +        } + +        return 0; +} + +int +afr_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	    size_t len, dict_t *xdata) +{ +        afr_private_t * priv  = NULL; +        afr_local_t   * local = NULL; +        call_frame_t   *transaction_frame = NULL; +        int ret = -1; +        int op_errno = 0; + +        VALIDATE_OR_GOTO (frame, out); +        VALIDATE_OR_GOTO (this, out); +        VALIDATE_OR_GOTO (this->private, out); + +        priv = this->private; + +        if (afr_is_split_brain (this, fd->inode)) { +                op_errno = EIO; +                goto out; +        } +        QUORUM_CHECK(discard, out); + +        AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out); +        local = frame->local; + +        ret = afr_local_init (local, priv, &op_errno); +        if (ret < 0) +                goto out; + +        local->cont.discard.offset  = offset; +	local->cont.discard.len = len; + +        local->fd = fd_ref (fd); + +        afr_open_fd_fix (fd, this); + +        afr_do_discard(frame, this); + +        ret = 0; +out: +        if (ret < 0) { +                if (transaction_frame) +                        AFR_STACK_DESTROY (transaction_frame); +                AFR_STACK_UNWIND (discard, frame, -1, op_errno, NULL, NULL, NULL); +        } + +        return 0; +} + +/* }}} */ +  /* {{{ fsync */  int32_t diff --git a/xlators/cluster/afr/src/afr.c b/xlators/cluster/afr/src/afr.c index 4d6c71480..6fabc0017 100644 --- a/xlators/cluster/afr/src/afr.c +++ b/xlators/cluster/afr/src/afr.c @@ -484,6 +484,7 @@ struct xlator_fops fops = {          .entrylk     = afr_entrylk,          .fentrylk    = afr_fentrylk,  	.fallocate   = afr_fallocate, +	.discard     = afr_discard,          /* inode read */          .access      = afr_access, diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h index 185f4f713..ced4e6fab 100644 --- a/xlators/cluster/afr/src/afr.h +++ b/xlators/cluster/afr/src/afr.h @@ -660,6 +660,14 @@ typedef struct _afr_local {  			struct iatt prebuf;  			struct iatt postbuf;  		} fallocate; + +		struct { +			off_t offset; +			size_t len; +			struct iatt prebuf; +			struct iatt postbuf; +		} discard; +          } cont;          struct { diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h index de35e843f..fb90e48cc 100644 --- a/xlators/cluster/dht/src/dht-common.h +++ b/xlators/cluster/dht/src/dht-common.h @@ -693,6 +693,8 @@ int32_t dht_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd,                        struct iatt  *stbuf, int32_t valid, dict_t *xdata);  int32_t dht_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd,  		      int32_t mode, off_t offset, size_t len, dict_t *xdata); +int32_t dht_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, +		    off_t offset, size_t len, dict_t *xdata);  int32_t dht_init (xlator_t *this);  void    dht_fini (xlator_t *this); diff --git a/xlators/cluster/dht/src/dht-inode-write.c b/xlators/cluster/dht/src/dht-inode-write.c index 56ed36ef0..9bcd84ae1 100644 --- a/xlators/cluster/dht/src/dht-inode-write.c +++ b/xlators/cluster/dht/src/dht-inode-write.c @@ -20,6 +20,7 @@ int dht_writev2 (xlator_t *this, call_frame_t *frame, int ret);  int dht_truncate2 (xlator_t *this, call_frame_t *frame, int ret);  int dht_setattr2 (xlator_t *this, call_frame_t *frame, int ret);  int dht_fallocate2(xlator_t *this, call_frame_t *frame, int op_ret); +int dht_discard2(xlator_t *this, call_frame_t *frame, int op_ret);  int  dht_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, @@ -488,6 +489,141 @@ err:  } +int +dht_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                int op_ret, int op_errno, struct iatt *prebuf, +                struct iatt *postbuf, dict_t *xdata) +{ +        dht_local_t  *local = NULL; +        call_frame_t *prev = NULL; +        int           ret = -1; + +        GF_VALIDATE_OR_GOTO ("dht", frame, err); +        GF_VALIDATE_OR_GOTO ("dht", this, out); +        GF_VALIDATE_OR_GOTO ("dht", frame->local, out); +        GF_VALIDATE_OR_GOTO ("dht", cookie, out); + +        local = frame->local; +        prev = cookie; + +        if ((op_ret == -1) && (op_errno != ENOENT)) { +                local->op_errno = op_errno; +                local->op_ret = -1; +                gf_log (this->name, GF_LOG_DEBUG, +                        "subvolume %s returned -1 (%s)", +                        prev->this->name, strerror (op_errno)); + +                goto out; +        } + +        if (local->call_cnt != 1) { +                if (local->stbuf.ia_blocks) { +                        dht_iatt_merge (this, postbuf, &local->stbuf, NULL); +                        dht_iatt_merge (this, prebuf, &local->prebuf, NULL); +                } +                goto out; +        } +        local->rebalance.target_op_fn = dht_discard2; + +        /* Phase 2 of migration */ +        if ((op_ret == -1) || IS_DHT_MIGRATION_PHASE2 (postbuf)) { +                ret = dht_rebalance_complete_check (this, frame); +                if (!ret) +                        return 0; +        } + +        /* Check if the rebalance phase1 is true */ +        if (IS_DHT_MIGRATION_PHASE1 (postbuf)) { +                dht_iatt_merge (this, &local->stbuf, postbuf, NULL); +                dht_iatt_merge (this, &local->prebuf, prebuf, NULL); +                ret = fd_ctx_get (local->fd, this, NULL); +                if (!ret) { +                        dht_discard2 (this, frame, 0); +                        return 0; +                } +                ret = dht_rebalance_in_progress_check (this, frame); +                if (!ret) +                        return 0; +        } + +out: +        DHT_STRIP_PHASE1_FLAGS (postbuf); +        DHT_STRIP_PHASE1_FLAGS (prebuf); +        DHT_STACK_UNWIND (discard, frame, op_ret, op_errno, +                          prebuf, postbuf, xdata); +err: +        return 0; +} + +int +dht_discard2(xlator_t *this, call_frame_t *frame, int op_ret) +{ +        dht_local_t  *local  = NULL; +        xlator_t     *subvol = NULL; +        uint64_t      tmp_subvol = 0; +        int           ret = -1; + +        local = frame->local; + +        if (local->fd) +                ret = fd_ctx_get (local->fd, this, &tmp_subvol); +        if (!ret) +                subvol = (xlator_t *)(long)tmp_subvol; + +        if (!subvol) +                subvol = local->cached_subvol; + +        local->call_cnt = 2; /* This is the second attempt */ + +	STACK_WIND(frame, dht_discard_cbk, subvol, subvol->fops->discard, +		   local->fd, local->rebalance.offset, local->rebalance.size, +		   NULL); + +        return 0; +} + +int +dht_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	    size_t len, dict_t *xdata) +{ +        xlator_t     *subvol = NULL; +        int           op_errno = -1; +        dht_local_t  *local = NULL; + +        VALIDATE_OR_GOTO (frame, err); +        VALIDATE_OR_GOTO (this, err); +        VALIDATE_OR_GOTO (fd, err); + +        local = dht_local_init (frame, NULL, fd, GF_FOP_DISCARD); +        if (!local) { +                op_errno = ENOMEM; +                goto err; +        } + +        local->rebalance.offset = offset; +	local->rebalance.size = len; + +        local->call_cnt = 1; +        subvol = local->cached_subvol; +        if (!subvol) { +                gf_log (this->name, GF_LOG_DEBUG, +                        "no cached subvolume for fd=%p", fd); +                op_errno = EINVAL; +                goto err; +        } + +        STACK_WIND (frame, dht_discard_cbk, subvol, subvol->fops->discard, +                    fd, offset, len, xdata); + +        return 0; + +err: +        op_errno = (op_errno == -1) ? errno : op_errno; +        DHT_STACK_UNWIND (discard, frame, -1, op_errno, NULL, NULL, NULL); + +        return 0; +} +  /* handle cases of migration here for 'setattr()' calls */  int  dht_file_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, diff --git a/xlators/cluster/dht/src/dht.c b/xlators/cluster/dht/src/dht.c index d3031e203..0349b63a9 100644 --- a/xlators/cluster/dht/src/dht.c +++ b/xlators/cluster/dht/src/dht.c @@ -71,6 +71,7 @@ struct xlator_fops fops = {          .setattr     = dht_setattr,          .fsetattr    = dht_fsetattr,  	.fallocate   = dht_fallocate, +	.discard     = dht_discard,  };  struct xlator_dumpops dumpops = { diff --git a/xlators/cluster/stripe/src/stripe.c b/xlators/cluster/stripe/src/stripe.c index 3c56464b8..c1294bdd4 100644 --- a/xlators/cluster/stripe/src/stripe.c +++ b/xlators/cluster/stripe/src/stripe.c @@ -3941,6 +3941,172 @@ err:  int32_t +stripe_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                   int32_t op_ret, int32_t op_errno, struct iatt *prebuf, +                   struct iatt *postbuf, dict_t *xdata) +{ +        int32_t         callcnt = 0; +        stripe_local_t *local = NULL; +	stripe_local_t *mlocal = NULL; +        call_frame_t   *prev = NULL; +	call_frame_t   *mframe = NULL; + +        if (!this || !frame || !frame->local || !cookie) { +                gf_log ("stripe", GF_LOG_DEBUG, "possible NULL deref"); +                goto out; +        } + +        prev  = cookie; +        local = frame->local; +	mframe = local->orig_frame; +	mlocal = mframe->local; + +        LOCK(&frame->lock); +        { +                callcnt = ++mlocal->call_count; + +                if (op_ret == 0) { +                        mlocal->post_buf = *postbuf; +                        mlocal->pre_buf = *prebuf; + +			mlocal->prebuf_blocks  += prebuf->ia_blocks; +			mlocal->postbuf_blocks += postbuf->ia_blocks; + +			correct_file_size(prebuf, mlocal->fctx, prev); +			correct_file_size(postbuf, mlocal->fctx, prev); + +			if (mlocal->prebuf_size < prebuf->ia_size) +				mlocal->prebuf_size = prebuf->ia_size; +			if (mlocal->postbuf_size < postbuf->ia_size) +				mlocal->postbuf_size = postbuf->ia_size; +                } + +		/* return the first failure */ +		if (mlocal->op_ret == 0) { +			mlocal->op_ret = op_ret; +			mlocal->op_errno = op_errno; +		} +        } +        UNLOCK (&frame->lock); + +        if ((callcnt == mlocal->wind_count) && mlocal->unwind) { +		mlocal->pre_buf.ia_size = mlocal->prebuf_size; +		mlocal->pre_buf.ia_blocks = mlocal->prebuf_blocks; +		mlocal->post_buf.ia_size = mlocal->postbuf_size; +		mlocal->post_buf.ia_blocks = mlocal->postbuf_blocks; + +                STRIPE_STACK_UNWIND (discard, mframe, mlocal->op_ret, +                                     mlocal->op_errno, &mlocal->pre_buf, +                                     &mlocal->post_buf, NULL); +        } +out: +	STRIPE_STACK_DESTROY(frame); +        return 0; +} + +int32_t +stripe_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	       size_t len, dict_t *xdata) +{ +        stripe_local_t   *local = NULL; +        stripe_fd_ctx_t  *fctx = NULL; +        int32_t           op_errno = 1; +        int32_t           idx = 0; +        int32_t           offset_offset = 0; +        int32_t           remaining_size = 0; +        off_t             fill_size = 0; +        uint64_t          stripe_size = 0; +        uint64_t          tmp_fctx = 0; +	off_t		  dest_offset = 0; +	call_frame_t	  *fframe = NULL; +	stripe_local_t	  *flocal = NULL; + +        VALIDATE_OR_GOTO (frame, err); +        VALIDATE_OR_GOTO (this, err); +        VALIDATE_OR_GOTO (fd, err); +        VALIDATE_OR_GOTO (fd->inode, err); + +        inode_ctx_get (fd->inode, this, &tmp_fctx); +        if (!tmp_fctx) { +                op_errno = EINVAL; +                goto err; +        } +        fctx = (stripe_fd_ctx_t *)(long)tmp_fctx; +        stripe_size = fctx->stripe_size; + +        STRIPE_VALIDATE_FCTX (fctx, err); + +        remaining_size = len; + +        local = mem_get0 (this->local_pool); +        if (!local) { +                op_errno = ENOMEM; +                goto err; +        } +        frame->local = local; +        local->stripe_size = stripe_size; +	local->fctx = fctx; + +        if (!stripe_size) { +                gf_log (this->name, GF_LOG_DEBUG, +                        "Wrong stripe size for the file"); +                op_errno = EINVAL; +                goto err; +        } + +        while (1) { +		fframe = copy_frame(frame); +		flocal = mem_get0(this->local_pool); +		if (!flocal) { +			op_errno = ENOMEM; +			goto err; +		} +		flocal->orig_frame = frame; +		fframe->local = flocal; + +		/* send discard request to the associated child node */ +                idx = (((offset + offset_offset) / +                        local->stripe_size) % fctx->stripe_count); + +                fill_size = (local->stripe_size - +                             ((offset + offset_offset) % local->stripe_size)); +                if (fill_size > remaining_size) +                        fill_size = remaining_size; + +                remaining_size -= fill_size; + +                local->wind_count++; +                if (remaining_size == 0) +                        local->unwind = 1; + +		dest_offset = offset + offset_offset; +		if (fctx->stripe_coalesce) +			dest_offset = coalesced_offset(dest_offset, +					local->stripe_size, fctx->stripe_count); + +		/* +		 * TODO: Create a separate handler for coalesce mode that sends a +		 * single discard per-child (since the ranges are linear). +		 */ +		STACK_WIND(fframe, stripe_discard_cbk, fctx->xl_array[idx], +			   fctx->xl_array[idx]->fops->discard, fd, dest_offset, +			   fill_size, xdata); + +                offset_offset += fill_size; +                if (remaining_size == 0) +                        break; +        } + +        return 0; +err: +	if (fframe) +		STRIPE_STACK_DESTROY(fframe); + +        STRIPE_STACK_UNWIND (discard, frame, -1, op_errno, NULL, NULL, NULL); +        return 0; +} + +int32_t  stripe_release (xlator_t *this, fd_t *fd)  {  	return 0; @@ -5389,6 +5555,7 @@ struct xlator_fops fops = {          .fremovexattr   = stripe_fremovexattr,          .readdirp       = stripe_readdirp,  	.fallocate	= stripe_fallocate, +	.discard	= stripe_discard,  };  struct xlator_cbks cbks = { diff --git a/xlators/debug/io-stats/src/io-stats.c b/xlators/debug/io-stats/src/io-stats.c index 5bb0e9d61..4f27a2e41 100644 --- a/xlators/debug/io-stats/src/io-stats.c +++ b/xlators/debug/io-stats/src/io-stats.c @@ -1736,6 +1736,18 @@ io_stats_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,  int +io_stats_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +		     int32_t op_ret, int32_t op_errno, struct iatt *prebuf, +		     struct iatt *postbuf, dict_t *xdata) +{ +	UPDATE_PROFILE_STATS(frame, DISCARD); +	STACK_UNWIND_STRICT(discard, frame, op_ret, op_errno, prebuf, postbuf, +			    xdata); +	return 0; +} + + +int  io_stats_lk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                   int32_t op_ret, int32_t op_errno, struct gf_flock *lock, dict_t *xdata)  { @@ -2416,6 +2428,20 @@ io_stats_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode,  	return 0;  } + +int +io_stats_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +		 size_t len, dict_t *xdata) +{ +	START_FOP_LATENCY(frame); + +	STACK_WIND(frame, io_stats_discard_cbk, FIRST_CHILD(this), +		   FIRST_CHILD(this)->fops->discard, fd, offset, len, xdata); + +	return 0; +} + +  int  io_stats_lk (call_frame_t *frame, xlator_t *this,               fd_t *fd, int32_t cmd, struct gf_flock *lock, dict_t *xdata) @@ -2843,6 +2869,7 @@ struct xlator_fops fops = {          .setattr     = io_stats_setattr,          .fsetattr    = io_stats_fsetattr,  	.fallocate   = io_stats_fallocate, +	.discard     = io_stats_discard,  };  struct xlator_cbks cbks = { diff --git a/xlators/features/marker/src/marker.c b/xlators/features/marker/src/marker.c index 2dc03f931..112e71dff 100644 --- a/xlators/features/marker/src/marker.c +++ b/xlators/features/marker/src/marker.c @@ -1876,6 +1876,75 @@ err:          return 0;  } + +int32_t +marker_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                   int32_t op_ret, int32_t op_errno, struct iatt *prebuf, +                   struct iatt *postbuf, dict_t *xdata) +{ +        marker_local_t     *local   = NULL; +        marker_conf_t      *priv    = NULL; + +        if (op_ret == -1) { +                gf_log (this->name, GF_LOG_TRACE, "%s occurred during discard", +                        strerror (op_errno)); +        } + +        local = (marker_local_t *) frame->local; + +        frame->local = NULL; + +        STACK_UNWIND_STRICT (discard, frame, op_ret, op_errno, prebuf, +                             postbuf, xdata); + +        if (op_ret == -1 || local == NULL) +                goto out; + +        priv = this->private; + +        if (priv->feature_enabled & GF_QUOTA) +                mq_initiate_quota_txn (this, &local->loc); + +        if (priv->feature_enabled & GF_XTIME) +                marker_xtime_update_marks (this, local); +out: +        marker_local_unref (local); + +        return 0; +} + +int32_t +marker_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	       size_t len, dict_t *xdata) +{ +        int32_t          ret   = 0; +        marker_local_t  *local = NULL; +        marker_conf_t   *priv  = NULL; + +        priv = this->private; + +        if (priv->feature_enabled == 0) +                goto wind; + +        local = mem_get0 (this->local_pool); + +        MARKER_INIT_LOCAL (frame, local); + +        ret = marker_inode_loc_fill (fd->inode, &local->loc); + +        if (ret == -1) +                goto err; +wind: +        STACK_WIND (frame, marker_discard_cbk, FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->discard, fd, offset, len, xdata); +        return 0; +err: +        STACK_UNWIND_STRICT (discard, frame, -1, ENOMEM, NULL, NULL, NULL); + +        return 0; +} + +  /* when a call from the special client is received on   * key trusted.glusterfs.volume-mark with value "RESET"   * or if the value is 0length, update the change the @@ -2686,6 +2755,7 @@ struct xlator_fops fops = {          .getxattr    = marker_getxattr,          .readdirp    = marker_readdirp,  	.fallocate   = marker_fallocate, +	.discard     = marker_discard,  };  struct xlator_cbks cbks = { diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index 59472b914..1b97d4302 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -2669,10 +2669,13 @@ fuse_fallocate_resume(fuse_state_t *state)  	       state->finh->unique, state->fd, state->flags, state->size,  	       state->off); -	/* we only support KEEP_SIZE */ -	FUSE_FOP(state, fuse_fallocate_cbk, GF_FOP_FALLOCATE, fallocate, state->fd, -		 (state->flags & FALLOC_FL_KEEP_SIZE), state->off, state->size, -		 state->xdata); +	if (state->flags & FALLOC_FL_PUNCH_HOLE) +		FUSE_FOP(state, fuse_fallocate_cbk, GF_FOP_DISCARD, discard, +			 state->fd, state->off, state->size, state->xdata); +	else +		FUSE_FOP(state, fuse_fallocate_cbk, GF_FOP_FALLOCATE, fallocate, +			 state->fd, (state->flags & FALLOC_FL_KEEP_SIZE), +			 state->off, state->size, state->xdata);  }  static void @@ -2687,13 +2690,6 @@ fuse_fallocate(xlator_t *this, fuse_in_header_t *finh, void *msg)  	state->flags = ffi->mode;  	state->fd = FH_TO_FD(ffi->fh); -	/* discard TBD as separate FOP */ -	if (state->flags & FALLOC_FL_PUNCH_HOLE) { -		send_fuse_err(this, finh, EOPNOTSUPP); -		free_fuse_state(state); -		return; -	} -  	fuse_resolve_fd_init(state, &state->resolve, state->fd);  	fuse_resolve_and_resume(state, fuse_fallocate_resume);  } diff --git a/xlators/performance/io-cache/src/io-cache.c b/xlators/performance/io-cache/src/io-cache.c index 30dc14a9c..d0667e469 100644 --- a/xlators/performance/io-cache/src/io-cache.c +++ b/xlators/performance/io-cache/src/io-cache.c @@ -1422,6 +1422,33 @@ ioc_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,          return 0;  } +static int32_t +ioc_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +		int32_t op_ret, int32_t op_errno, struct iatt *pre, +		struct iatt *post, dict_t *xdata) +{ +	STACK_UNWIND_STRICT(discard, frame, op_ret, op_errno, pre, post, xdata); +	return 0; +} + +static int32_t +ioc_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	    size_t len, dict_t *xdata) +{ +	uint64_t ioc_inode = 0; + +	inode_ctx_get (fd->inode, this, &ioc_inode); + +	if (ioc_inode) +		ioc_inode_flush ((ioc_inode_t *)(long)ioc_inode); + +	STACK_WIND(frame, ioc_discard_cbk, FIRST_CHILD(this), +		   FIRST_CHILD(this)->fops->discard, fd, offset, len, xdata); +       return 0; +} + + +  int32_t  ioc_get_priority_list (const char *opt_str, struct list_head *first)  { @@ -2044,6 +2071,7 @@ struct xlator_fops fops = {          .mknod       = ioc_mknod,          .readdirp    = ioc_readdirp, +	.discard     = ioc_discard,  }; diff --git a/xlators/performance/io-threads/src/io-threads.c b/xlators/performance/io-threads/src/io-threads.c index 33642bffb..c6bdc3754 100644 --- a/xlators/performance/io-threads/src/io-threads.c +++ b/xlators/performance/io-threads/src/io-threads.c @@ -308,6 +308,7 @@ iot_schedule (call_frame_t *frame, xlator_t *this, call_stub_t *stub)          case GF_FOP_FXATTROP:          case GF_FOP_RCHECKSUM:  	case GF_FOP_FALLOCATE: +	case GF_FOP_DISCARD:                  pri = IOT_PRI_LO;                  break; @@ -2459,6 +2460,56 @@ out:  }  int +iot_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                  int32_t op_ret, int32_t op_errno, +                  struct iatt *preop, struct iatt *postop, dict_t *xdata) +{ +        STACK_UNWIND_STRICT (discard, frame, op_ret, op_errno, preop, postop, +                             xdata); +        return 0; +} + + +int +iot_discard_wrapper(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +		    size_t len, dict_t *xdata) +{ +        STACK_WIND (frame, iot_discard_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->discard, fd, offset, len, xdata); +        return 0; +} + + +int +iot_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	    size_t len, dict_t *xdata) +{ +        call_stub_t     *stub = NULL; +        int              ret = -1; + +        stub = fop_discard_stub(frame, iot_discard_wrapper, fd, offset, len, +				xdata); +        if (!stub) { +                gf_log (this->name, GF_LOG_ERROR, "cannot create discard stub" +                        "(out of memory)"); +                ret = -ENOMEM; +                goto out; +        } + +        ret = iot_schedule (frame, this, stub); + +out: +        if (ret < 0) { +                STACK_UNWIND_STRICT (discard, frame, -1, -ret, NULL, NULL, +                                     NULL); +                if (stub != NULL) { +                        call_stub_destroy (stub); +                } +        } +        return 0; +} + +int  __iot_workers_scale (iot_conf_t *conf)  {          int       scale = 0; @@ -2788,6 +2839,7 @@ struct xlator_fops fops = {  	.fxattrop    = iot_fxattrop,          .rchecksum   = iot_rchecksum,  	.fallocate   = iot_fallocate, +	.discard     = iot_discard,  };  struct xlator_cbks cbks; diff --git a/xlators/performance/md-cache/src/md-cache.c b/xlators/performance/md-cache/src/md-cache.c index 0b2c94319..2f52cbe58 100644 --- a/xlators/performance/md-cache/src/md-cache.c +++ b/xlators/performance/md-cache/src/md-cache.c @@ -1889,6 +1889,45 @@ int mdc_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode,  }  int +mdc_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                int32_t op_ret, int32_t op_errno, +                struct iatt *prebuf, struct iatt *postbuf, dict_t *xdata) +{ +        mdc_local_t  *local = NULL; + +        local = frame->local; + +        if (op_ret != 0) +                goto out; + +        if (!local) +                goto out; + +        mdc_inode_iatt_set_validate(this, local->fd->inode, prebuf, postbuf); + +out: +        MDC_STACK_UNWIND(discard, frame, op_ret, op_errno, prebuf, postbuf, +                         xdata); + +        return 0; +} + +int mdc_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +		size_t len, dict_t *xdata) +{ +	mdc_local_t *local; + +	local = mdc_local_get(frame); +	local->fd = fd_ref(fd); + +	STACK_WIND(frame, mdc_discard_cbk, FIRST_CHILD(this), +		   FIRST_CHILD(this)->fops->discard, fd, offset, len, +		   xdata); + +	return 0; +} + +int  mdc_forget (xlator_t *this, inode_t *inode)  {          mdc_inode_wipe (this, inode); @@ -2017,6 +2056,7 @@ struct xlator_fops fops = {  	.readdirp    = mdc_readdirp,  	.readdir     = mdc_readdir,  	.fallocate   = mdc_fallocate, +	.discard     = mdc_discard,  }; diff --git a/xlators/performance/open-behind/src/open-behind.c b/xlators/performance/open-behind/src/open-behind.c index 5ac813132..26b684e88 100644 --- a/xlators/performance/open-behind/src/open-behind.c +++ b/xlators/performance/open-behind/src/open-behind.c @@ -701,6 +701,25 @@ err:  }  int +ob_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	   size_t len, dict_t *xdata) +{ +	call_stub_t *stub; + +	stub = fop_discard_stub(frame, default_discard_resume, fd, offset, len, +				xdata); +	if (!stub) +		goto err; + +	open_and_resume(this, fd, stub); + +	return 0; +err: +	STACK_UNWIND_STRICT(discard, frame, -1, ENOMEM, NULL, NULL, NULL); +	return 0; +} + +int  ob_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags,  	   dict_t *xdata)  { @@ -922,6 +941,7 @@ struct xlator_fops fops = {  	.fxattrop    = ob_fxattrop,  	.fsetattr    = ob_fsetattr,  	.fallocate   = ob_fallocate, +	.discard     = ob_discard,  	.unlink      = ob_unlink,  	.rename      = ob_rename,  	.lk          = ob_lk, diff --git a/xlators/performance/read-ahead/src/read-ahead.c b/xlators/performance/read-ahead/src/read-ahead.c index 522fa52b8..241fa477f 100644 --- a/xlators/performance/read-ahead/src/read-ahead.c +++ b/xlators/performance/read-ahead/src/read-ahead.c @@ -942,6 +942,55 @@ unwind:          return 0;  } +int +ra_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +               int32_t op_ret, int32_t op_errno, struct iatt *prebuf, +               struct iatt *postbuf, dict_t *xdata) +{ +        GF_ASSERT (frame); + +        STACK_UNWIND_STRICT (discard, frame, op_ret, op_errno, prebuf, +                             postbuf, xdata); +        return 0; +} + +static int +ra_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	     size_t len, dict_t *xdata) +{ +        ra_file_t *file    = NULL; +        fd_t      *iter_fd = NULL; +        inode_t   *inode   = NULL; +        uint64_t  tmp_file = 0; +        int32_t   op_errno = EINVAL; + +        GF_ASSERT (frame); +        GF_VALIDATE_OR_GOTO (frame->this->name, this, unwind); +        GF_VALIDATE_OR_GOTO (frame->this->name, fd, unwind); + +        inode = fd->inode; + +        LOCK (&inode->lock); +        { +                list_for_each_entry (iter_fd, &inode->fd_list, inode_list) { +                        fd_ctx_get (iter_fd, this, &tmp_file); +                        file = (ra_file_t *)(long)tmp_file; +                        if (!file) +                                continue; + +                        flush_region(frame, file, offset, len, 1); +                } +        } +        UNLOCK (&inode->lock); + +        STACK_WIND (frame, ra_discard_cbk, FIRST_CHILD (this), +                    FIRST_CHILD (this)->fops->discard, fd, offset, len, xdata); +        return 0; + +unwind: +        STACK_UNWIND_STRICT (discard, frame, -1, op_errno, NULL, NULL, NULL); +        return 0; +}  int  ra_priv_dump (xlator_t *this) @@ -1123,6 +1172,7 @@ struct xlator_fops fops = {          .truncate    = ra_truncate,          .ftruncate   = ra_ftruncate,          .fstat       = ra_fstat, +	.discard     = ra_discard,  };  struct xlator_cbks cbks = { diff --git a/xlators/protocol/client/src/client-rpc-fops.c b/xlators/protocol/client/src/client-rpc-fops.c index 53cf3968a..c05542834 100644 --- a/xlators/protocol/client/src/client-rpc-fops.c +++ b/xlators/protocol/client/src/client-rpc-fops.c @@ -1993,6 +1993,61 @@ out:  }  int +client3_3_discard_cbk(struct rpc_req *req, struct iovec *iov, int count, +		      void *myframe) +{ +        call_frame_t    *frame      = NULL; +        gfs3_discard_rsp rsp      = {0,}; +        struct iatt      prestat    = {0,}; +        struct iatt      poststat   = {0,}; +        int              ret        = 0; +        xlator_t *this       = NULL; +        dict_t  *xdata       = NULL; + +        this = THIS; + +        frame = myframe; + +        if (-1 == req->rpc_status) { +                rsp.op_ret   = -1; +                rsp.op_errno = ENOTCONN; +                goto out; +        } +        ret = xdr_to_generic(*iov, &rsp, (xdrproc_t) xdr_gfs3_discard_rsp); +        if (ret < 0) { +                gf_log (this->name, GF_LOG_ERROR, "XDR decoding failed"); +                rsp.op_ret   = -1; +                rsp.op_errno = EINVAL; +                goto out; +        } + +        if (-1 != rsp.op_ret) { +                gf_stat_to_iatt (&rsp.statpre, &prestat); +                gf_stat_to_iatt (&rsp.statpost, &poststat); +        } + +        GF_PROTOCOL_DICT_UNSERIALIZE (this, xdata, (rsp.xdata.xdata_val), +                                      (rsp.xdata.xdata_len), ret, +                                      rsp.op_errno, out); + +out: +        if (rsp.op_ret == -1) { +                gf_log (this->name, GF_LOG_WARNING, "remote operation failed: %s", +                        strerror (gf_error_to_errno (rsp.op_errno))); +        } +        CLIENT_STACK_UNWIND (discard, frame, rsp.op_ret, +                             gf_error_to_errno (rsp.op_errno), &prestat, +                             &poststat, xdata); + +        free (rsp.xdata.xdata_val); + +        if (xdata) +                dict_unref (xdata); + +        return 0; +} + +int  client3_3_setattr_cbk (struct rpc_req *req, struct iovec *iov, int count,                         void *myframe)  { @@ -5888,6 +5943,50 @@ unwind:          return 0;  } +int32_t +client3_3_discard(call_frame_t *frame, xlator_t *this, void *data) +{ +        clnt_args_t       *args     = NULL; +        int64_t            remote_fd = -1; +        clnt_conf_t       *conf     = NULL; +	gfs3_discard_req   req	    = {{0},}; +        int                op_errno = ESTALE; +        int                ret        = 0; + +        if (!frame || !this || !data) +                goto unwind; + +        args = data; +        conf = this->private; + +        CLIENT_GET_REMOTE_FD (this, args->fd, DEFAULT_REMOTE_FD, +                              remote_fd, op_errno, unwind); + +        req.fd = remote_fd; +	req.offset = args->offset; +	req.size = args->size; +	memcpy(req.gfid, args->fd->inode->gfid, 16); + +        GF_PROTOCOL_DICT_SERIALIZE (this, args->xdata, (&req.xdata.xdata_val), +                                    req.xdata.xdata_len, op_errno, unwind); + +        ret = client_submit_request(this, &req, frame, conf->fops, +                                    GFS3_OP_DISCARD, client3_3_discard_cbk, +				    NULL, NULL, 0, NULL, 0, NULL, +                                    (xdrproc_t) xdr_gfs3_discard_req); +        if (ret) +                gf_log (this->name, GF_LOG_WARNING, "failed to send the fop"); + +        GF_FREE (req.xdata.xdata_val); + +        return 0; +unwind: +        CLIENT_STACK_UNWIND(discard, frame, -1, op_errno, NULL, NULL, NULL); +        GF_FREE (req.xdata.xdata_val); + +        return 0; +} +  /* Table Specific to FOPS */ @@ -5934,6 +6033,7 @@ rpc_clnt_procedure_t clnt3_3_fop_actors[GF_FOP_MAXVALUE] = {          [GF_FOP_FSETATTR]    = { "FSETATTR",    client3_3_fsetattr },          [GF_FOP_READDIRP]    = { "READDIRP",    client3_3_readdirp },  	[GF_FOP_FALLOCATE]   = { "FALLOCATE",	client3_3_fallocate }, +	[GF_FOP_DISCARD]     = { "DISCARD",	client3_3_discard },          [GF_FOP_RELEASE]     = { "RELEASE",     client3_3_release },          [GF_FOP_RELEASEDIR]  = { "RELEASEDIR",  client3_3_releasedir },          [GF_FOP_GETSPEC]     = { "GETSPEC",     client3_getspec }, @@ -5984,6 +6084,7 @@ char *clnt3_3_fop_names[GFS3_OP_MAXVALUE] = {          [GFS3_OP_FSETATTR]    = "FSETATTR",          [GFS3_OP_READDIRP]    = "READDIRP",  	[GFS3_OP_FALLOCATE]   = "FALLOCATE", +	[GFS3_OP_DISCARD]     = "DISCARD",          [GFS3_OP_RELEASE]     = "RELEASE",          [GFS3_OP_RELEASEDIR]  = "RELEASEDIR",          [GFS3_OP_FREMOVEXATTR] = "FREMOVEXATTR", diff --git a/xlators/protocol/client/src/client.c b/xlators/protocol/client/src/client.c index 377263af6..aa2b8eef8 100644 --- a/xlators/protocol/client/src/client.c +++ b/xlators/protocol/client/src/client.c @@ -1997,6 +1997,40 @@ out:  }  int32_t +client_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	       size_t len, dict_t *xdata) +{ +        int          ret  = -1; +        clnt_conf_t *conf = NULL; +        rpc_clnt_procedure_t *proc = NULL; +        clnt_args_t  args = {0,}; + +        conf = this->private; +        if (!conf || !conf->fops) +                goto out; + +        args.fd = fd; +	args.offset = offset; +	args.size = len; +        args.xdata = xdata; + +        proc = &conf->fops->proctable[GF_FOP_DISCARD]; +        if (!proc) { +                gf_log (this->name, GF_LOG_ERROR, +                        "rpc procedure not found for %s", +                        gf_fop_list[GF_FOP_DISCARD]); +                goto out; +        } +        if (proc->fn) +                ret = proc->fn (frame, this, &args); +out: +        if (ret) +                STACK_UNWIND_STRICT(discard, frame, -1, ENOTCONN, NULL, NULL, NULL); + +	return 0; +} + +int32_t  client_getspec (call_frame_t *frame, xlator_t *this, const char *key,                  int32_t flags)  { @@ -2714,6 +2748,7 @@ struct xlator_fops fops = {          .setattr     = client_setattr,          .fsetattr    = client_fsetattr,  	.fallocate   = client_fallocate, +	.discard     = client_discard,          .getspec     = client_getspec,  }; diff --git a/xlators/protocol/server/src/server-rpc-fops.c b/xlators/protocol/server/src/server-rpc-fops.c index 4b847eabd..55e30fdd7 100644 --- a/xlators/protocol/server/src/server-rpc-fops.c +++ b/xlators/protocol/server/src/server-rpc-fops.c @@ -2008,6 +2008,45 @@ out:          return 0;  } +int +server_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                   int32_t op_ret, int32_t op_errno, +                   struct iatt *statpre, struct iatt *statpost, dict_t *xdata) +{ +        gfs3_discard_rsp rsp	 = {0,}; +        server_state_t    *state = NULL; +        rpcsvc_request_t  *req   = NULL; + +        req = frame->local; +        state  = CALL_STATE (frame); + +        GF_PROTOCOL_DICT_SERIALIZE (this, xdata, (&rsp.xdata.xdata_val), +                                    rsp.xdata.xdata_len, op_errno, out); + +        if (op_ret) { +                gf_log (this->name, GF_LOG_INFO, +                        "%"PRId64": DISCARD %"PRId64" (%s) ==> (%s)", +                        frame->root->unique, state->resolve.fd_no, +                        uuid_utoa (state->resolve.gfid), +                        strerror (op_errno)); +                goto out; +        } + +        gf_stat_from_iatt (&rsp.statpre, statpre); +        gf_stat_from_iatt (&rsp.statpost, statpost); + +out: +        rsp.op_ret    = op_ret; +        rsp.op_errno  = gf_errno_to_error (op_errno); + +        server_submit_reply(frame, req, &rsp, NULL, 0, NULL, +                            (xdrproc_t) xdr_gfs3_discard_rsp); + +        GF_FREE (rsp.xdata.xdata_val); + +        return 0; +} +  /* Resume function section */  int @@ -2975,6 +3014,26 @@ err:          return 0;  } +int +server_discard_resume (call_frame_t *frame, xlator_t *bound_xl) +{ +        server_state_t *state = NULL; + +        state = CALL_STATE (frame); + +        if (state->resolve.op_ret != 0) +                goto err; + +        STACK_WIND (frame, server_discard_cbk, +                    bound_xl, bound_xl->fops->discard, +                    state->fd, state->offset, state->size, state->xdata); +        return 0; +err: +        server_discard_cbk(frame, NULL, frame->this, state->resolve.op_ret, +			   state->resolve.op_errno, NULL, NULL, NULL); + +        return 0; +}  /* Fop section */ @@ -3213,6 +3272,68 @@ out:          return ret;  } + + +int +server3_3_discard(rpcsvc_request_t *req) +{ +        server_state_t    *state = NULL; +        call_frame_t      *frame = NULL; +        gfs3_discard_req args	 = {{0},}; +        int                ret   = -1; +        int                op_errno = 0; + +        if (!req) +                return ret; + +        ret = xdr_to_generic (req->msg[0], &args, +                              (xdrproc_t)xdr_gfs3_discard_req); +        if (ret < 0) { +                //failed to decode msg; +                req->rpc_err = GARBAGE_ARGS; +                goto out; +        } + +        frame = get_frame_from_request (req); +        if (!frame) { +                // something wrong, mostly insufficient memory +                req->rpc_err = GARBAGE_ARGS; /* TODO */ +                goto out; +        } +        frame->root->op = GF_FOP_DISCARD; + +        state = CALL_STATE (frame); +        if (!state->conn->bound_xl) { +                /* auth failure, request on subvolume without setvolume */ +                req->rpc_err = GARBAGE_ARGS; +                goto out; +        } + +        state->resolve.type   = RESOLVE_MUST; +        state->resolve.fd_no  = args.fd; + +	state->offset = args.offset; +	state->size = args.size; +	memcpy(state->resolve.gfid, args.gfid, 16); + +        GF_PROTOCOL_DICT_UNSERIALIZE (state->conn->bound_xl, state->xdata, +                                      (args.xdata.xdata_val), +                                      (args.xdata.xdata_len), ret, +                                      op_errno, out); + +        ret = 0; +        resolve_and_resume (frame, server_discard_resume); + +out: +        free (args.xdata.xdata_val); + +        if (op_errno) +                req->rpc_err = GARBAGE_ARGS; + +        return ret; +} + +  int  server3_3_readlink (rpcsvc_request_t *req)  { @@ -5867,6 +5988,7 @@ rpcsvc_actor_t glusterfs3_3_fop_actors[] = {          [GFS3_OP_FSETATTR]    = { "FSETATTR",   GFS3_OP_FSETATTR, server3_3_fsetattr, NULL, 0},          [GFS3_OP_READDIRP]    = { "READDIRP",   GFS3_OP_READDIRP, server3_3_readdirp, NULL, 0},  	[GFS3_OP_FALLOCATE]    = { "FALLOCATE",	GFS3_OP_FALLOCATE, server3_3_fallocate, NULL, 0}, +	[GFS3_OP_DISCARD]     = { "DISCARD",	GFS3_OP_DISCARD, server3_3_discard, NULL, 0},          [GFS3_OP_RELEASE]     = { "RELEASE",    GFS3_OP_RELEASE, server3_3_release, NULL, 0},          [GFS3_OP_RELEASEDIR]  = { "RELEASEDIR", GFS3_OP_RELEASEDIR, server3_3_releasedir, NULL, 0},          [GFS3_OP_FREMOVEXATTR] = { "FREMOVEXATTR", GFS3_OP_FREMOVEXATTR, server3_3_fremovexattr, NULL, 0}, diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 368834037..05101fd31 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -562,16 +562,12 @@ out:  }  static int32_t -_posix_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t keep_size, -		off_t offset, size_t len, dict_t *xdata) +posix_do_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, +		   off_t offset, size_t len, struct iatt *statpre, +		   struct iatt *statpost)  { -	int32_t        op_ret    = -1; -        int32_t        op_errno  = 0; -        struct iatt    statpre     = {0,}; -        struct iatt    statpost    = {0,};          struct posix_fd *pfd = NULL;          int32_t          ret = -1; -	int32_t		flags = 0;          DECLARE_OLD_FS_ID_VAR; @@ -583,48 +579,87 @@ _posix_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t keep_siz          ret = posix_fd_ctx_get (fd, this, &pfd);          if (ret < 0) { -                op_errno = -ret;                  gf_log (this->name, GF_LOG_DEBUG,                          "pfd is NULL from fd=%p", fd);                  goto out;          } -        op_ret = posix_fdstat (this, pfd->fd, &statpre); -        if (op_ret == -1) { -                op_errno = errno; +        ret = posix_fdstat (this, pfd->fd, statpre); +        if (ret == -1) { +                ret = -errno;                  gf_log (this->name, GF_LOG_ERROR,                          "fallocate (fstat) failed on fd=%p: %s", fd, -                        strerror (op_errno)); +                        strerror (errno));                  goto out;          } -	if (keep_size) -		flags = FALLOC_FL_KEEP_SIZE; - -	op_ret = sys_fallocate(pfd->fd, flags, offset, len); -	if (op_ret == -1) { -		op_errno = errno; +	ret = sys_fallocate(pfd->fd, flags, offset, len); +	if (ret == -1) { +		ret = -errno;  		goto out;  	} -        op_ret = posix_fdstat (this, pfd->fd, &statpost); -        if (op_ret == -1) { -                op_errno = errno; +        ret = posix_fdstat (this, pfd->fd, statpost); +        if (ret == -1) { +                ret = -errno;                  gf_log (this->name, GF_LOG_ERROR,                          "fallocate (fstat) failed on fd=%p: %s", fd, -                        strerror (op_errno)); +                        strerror (errno));                  goto out;          } -        op_ret = 0; -  out:          SET_TO_OLD_FS_ID (); -        STACK_UNWIND_STRICT (fallocate, frame, op_ret, op_errno, -                             &statpre, &statpost, NULL); +        return ret; +} + +static int32_t +_posix_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t keep_size, +		off_t offset, size_t len, dict_t *xdata) +{ +	int32_t ret; +	int32_t flags = 0; +        struct iatt statpre = {0,}; +        struct iatt statpost = {0,}; + +	if (keep_size) +		flags = FALLOC_FL_KEEP_SIZE; + +	ret = posix_do_fallocate(frame, this, fd, flags, offset, len, +				 &statpre, &statpost); +	if (ret < 0)  +		goto err; + +	STACK_UNWIND_STRICT(fallocate, frame, 0, 0, &statpre, &statpost, NULL); +	return 0; + +err: +	STACK_UNWIND_STRICT(fallocate, frame, -1, -ret, NULL, NULL, NULL); +	return 0; +} + +static int32_t +posix_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +	      size_t len, dict_t *xdata) +{ +	int32_t ret; +	int32_t flags = FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE; +        struct iatt statpre = {0,}; +        struct iatt statpost = {0,}; + +	ret = posix_do_fallocate(frame, this, fd, flags, offset, len, +				 &statpre, &statpost); +	if (ret < 0)  +		goto err; + +	STACK_UNWIND_STRICT(discard, frame, 0, 0, &statpre, &statpost, NULL); +	return 0; + +err: +	STACK_UNWIND_STRICT(discard, frame, -1, -ret, NULL, NULL, NULL); +	return 0; -        return 0;  }  int32_t @@ -4726,6 +4761,7 @@ struct xlator_fops fops = {          .setattr     = posix_setattr,          .fsetattr    = posix_fsetattr,  	.fallocate   = _posix_fallocate, +	.discard     = posix_discard,  };  struct xlator_cbks cbks = {  | 
