Example #1
0
int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
{
#if defined(HAVE_FSETXATTR)
	return fsetxattr(filedes, name, value, size, flags);
#elif defined(HAVE_ATTR_SETF)
	int myflags = 0;
	char *attrname = strchr(name,'.') +1;
	
	if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
	if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
	if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;

	return attr_setf(filedes, attrname, (const char *)value, size, myflags);
#else
	errno = ENOSYS;
	return -1;
#endif
}
Example #2
0
int sys_fsetxattr (int filedes, const char *uname, const void *value, size_t size, int flags)
{
    const char *name = prefix(uname);

#if defined(HAVE_FSETXATTR)
#ifndef XATTR_ADD_OPT
    return fsetxattr(filedes, name, value, size, flags);
#else
    int options = 0;
    return fsetxattr(filedes, name, value, size, 0, options);
#endif
#elif defined(HAVE_FSETEA)
    return fsetea(filedes, name, value, size, flags);
#elif defined(HAVE_EXTATTR_SET_FD)
    char *s;
    int retval = 0;
    int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
        EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
    const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
    if (flags) {
        /* Check attribute existence */
        retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
        if (retval < 0) {
            /* REPLACE attribute, that doesn't exist */
            if (flags & XATTR_REPLACE && errno == ENOATTR) {
                errno = ENOATTR;
                return -1;
            }
            /* Ignore other errors */
        }
        else {
            if (flags & XATTR_CREATE) {
                errno = EEXIST;
                return -1;
            }
        }
    }
    retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
    return (retval < 0) ? -1 : 0;
#elif defined(HAVE_ATTR_SETF)
    int myflags = 0;
    char *attrname = strchr(name,'.') + 1;

    if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
    if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
    if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;

    return attr_setf(filedes, attrname, (const char *)value, size, myflags);
#elif defined(HAVE_ATTROPEN)
    int ret = -1;
    int myflags = O_RDWR | O_XATTR;
    int attrfd;
    if (flags & XATTR_CREATE) myflags |= O_EXCL;
    if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
    attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
    if (attrfd >= 0) {
        ret = solaris_write_xattr(attrfd, value, size);
        close(attrfd);
    }
    return ret;
#else
    errno = ENOSYS;
    return -1;
#endif
}
Example #3
0
/*
 * Do the defragmentation of a single file.
 * We already are pretty sure we can and want to 
 * defragment the file.  Create the tmp file, copy
 * the data (maintaining holes) and call the kernel
 * extent swap routinte.
 */
static int
packfile(char *fname, char *tname, int fd, xfs_bstat_t *statp, int do_rt)
{
	int 		tfd;
	int		srval;
	int		nextents, extent, cur_nextents, new_nextents;
	unsigned	blksz_dio;
	unsigned	dio_min;
	struct dioattr	dio;
	static xfs_swapext_t   sx;
	struct xfs_flock64  space;
	off64_t 	cnt, pos;
	void 		*fbuf;
	int 		ct, wc, wc_b4;
	struct fsxattr  tfsx;
	char		ffname[SMBUFSZ];
	int		ffd = 0;

	/*
	 * Work out the extent map - nextents will be set to the
	 * minimum number of extents needed for the file (taking 
	 * into account holes), cur_nextents is the current number
	 * of extents.
	 */
	nextents = read_fd_bmap(fd, statp, &cur_nextents);

	if ( cur_nextents == 1 || cur_nextents <= nextents ) {
		if (vflag)
			fsrprintf("%s already fully defragmented.\n", fname);
		return 1; /* indicates no change/no error */
	}

	if (dflag)
		fsrprintf("%s extents=%d can_save=%d tmp=%s\n", 
		          fname, cur_nextents, (cur_nextents - nextents), 
		          tname);

	if ((tfd = open(tname, openopts, 0666)) < 0) {
		if (vflag)
			fsrprintf("could not open tmp as uid %d: %s: %s\n",
				   statp->bs_uid,tname, strerror(errno));
		return -1;
	}
	unlink(tname);

	/* Setup extended attributes */
	if( statp->bs_xflags & XFS_XFLAG_HASATTR ) {
		if (attr_setf(tfd, "X", "X", 1, ATTR_CREATE) != 0) {
			fsrprintf("could not set ATTR on tmp: %s:\n", tname);
			close(tfd);
			return -1;
		}
		if (dflag)
			fsrprintf("%s set temp attr\n", tname);
	}

	if ((ioctl(tfd, XFS_IOC_DIOINFO, &dio)) < 0 ) {
		fsrprintf("could not get I/O info on tmp: %s\n", tname);
		close(tfd);
		return -1;
	}

	if (do_rt) {
		int rt_textsize = fsgeom.rtextsize * fsgeom.blocksize;

		tfsx.fsx_xflags = XFS_XFLAG_REALTIME;

		if ((tfsx.fsx_extsize = rt_textsize) <= 0 ) {
			fsrprintf("realtime geom not avail for tmp: %s\n", fname);
			close(tfd);
			return -1;
		}

		if (ioctl( tfd,  XFS_IOC_FSSETXATTR, &tfsx) < 0) {
			fsrprintf("could not set rt on tmp: %s\n", tname);
			close(tfd);
			return -1;
		}
	}

	dio_min   = dio.d_miniosz;
	if (statp->bs_size <= dio_min)
		blksz_dio = dio_min;
	else {
		blksz_dio = min(dio.d_maxiosz, BUFFER_MAX - pagesize);
		if (argv_blksz_dio != 0)
			blksz_dio = min(argv_blksz_dio, blksz_dio);
		blksz_dio = (min(statp->bs_size, blksz_dio) / dio_min) * dio_min;
	}

	if (dflag) {
	    fsrprintf("DEBUG: fsize=%lld blsz_dio=%d d_min=%d d_max=%d pgsz=%d\n",
	    statp->bs_size, blksz_dio, dio.d_miniosz, dio.d_maxiosz, pagesize);
	}

	/* Malloc a buffer */
	if (! (fbuf = (char *)memalign(dio.d_mem, blksz_dio))) {
		fsrprintf("could not allocate buf: %s\n", tname);
		close(tfd);
		return -1;
	}

	if (nfrags) {
		/* Create new tmp file in same AG as first */
		sprintf(ffname, "%s.frag", tname);

		/* Open the new file for sync writes */
		if ((ffd = open(ffname, openopts, 0666)) 
		    < 0) {
			fsrprintf("could not open fragfile: %s : %s\n",
				   ffname, strerror(errno));
			return -1;
		}
		unlink(ffname);
	}

	/* Loop through block map copying the file. */
	for (extent = 0; extent < nextents; extent++) {
		pos = outmap[extent].bmv_offset;
		if (outmap[extent].bmv_block == -1) {
			space.l_whence = 0;
			space.l_start = pos;
			space.l_len = outmap[extent].bmv_length;
			if (ioctl(tfd, XFS_IOC_UNRESVSP64, &space) < 0) {
				fsrprintf("could not trunc tmp %s\n", 
					   tname);
			}
			lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR);
			lseek64(fd, outmap[extent].bmv_length, SEEK_CUR);
			continue;
		} else if (outmap[extent].bmv_length == 0) {
			/* to catch holes at the beginning of the file */
			continue;
		}
		if (! nfrags) {
			space.l_whence = SEEK_CUR;
			space.l_start = 0;
			space.l_len = outmap[extent].bmv_length;

			if (ioctl(tfd, XFS_IOC_RESVSP64, &space) < 0) {
				fsrprintf("could not pre-alloc tmp space: %s\n",
					  tname);
				close(tfd);
				free(fbuf);
				return -1;
			}
		}
		for (cnt = outmap[extent].bmv_length; cnt > 0;
		     cnt -= ct, pos += ct) {
			if (nfrags && --nfrags) {
				ct = min(cnt, dio_min);
			} else if (cnt % dio_min == 0) {
				ct = min(cnt, blksz_dio);
			} else {
				ct = min(cnt + dio_min - (cnt % dio_min), 
					blksz_dio);
			}
			ct = read(fd, fbuf, ct);
			if (ct == 0) {
				/* EOF, stop trying to read */
				extent = nextents;
				break;
			}
			/* Ensure we do direct I/O to correct block
			 * boundaries.
			 */
			if (ct % dio_min != 0) {
				wc = ct + dio_min - (ct % dio_min);
			} else {
				wc = ct;
			}
			wc_b4 = wc;
			if (ct < 0 || ((wc = write(tfd, fbuf, wc)) != wc_b4)) {
				if (ct < 0)
				fsrprintf("bad read of %d bytes from %s:%s\n",
				           wc_b4, fname, strerror(errno));
				else if (wc < 0)
				fsrprintf("bad write of %d bytes to %s: %s\n",
					   wc_b4, tname, strerror(errno));
				else {
					/*
					 * Might be out of space
					 *
					 * Try to finish write
					 */
					int resid = ct-wc;

					if ((wc = write(tfd, ((char *)fbuf)+wc,
							resid)) == resid) {
						/* worked on second attempt? */
						continue;
					}
					else
					if (wc < 0) {
				fsrprintf("bad write2 of %d bytes to %s: %s\n",
				           resid, tname, strerror(errno));
					} else {
						fsrprintf("bad copy to %s\n",
					           tname);
					}
				}
				free(fbuf);
				return -1;
			}
			if (nfrags) {
				/* Do a matching write to the tmp file */
				wc = wc_b4;
				if (((wc = write(ffd, fbuf, wc)) != wc_b4)) {						fsrprintf("bad write of %d bytes "
						  "to %s: %s\n",
					   wc_b4, ffname, strerror(errno));
				}
			}
		}
	}
	ftruncate64(tfd, statp->bs_size);
	if (ffd) close(ffd);
	fsync(tfd);

	free(fbuf);

	sx.sx_stat     = *statp; /* struct copy */
	sx.sx_version  = XFS_SX_VERSION;
	sx.sx_fdtarget = fd;
	sx.sx_fdtmp    = tfd;
	sx.sx_offset   = 0;
	sx.sx_length   = statp->bs_size;

	/* Check if the extent count improved */
	new_nextents = getnextents(tfd);
	if (cur_nextents <= new_nextents) {
		if (vflag)
			fsrprintf("No improvement made: %s\n", fname);
		close(tfd);
		return 1; /* no change/no error */
	}

	/* Swap the extents */
	srval = xfs_swapext(fd, &sx);
	if (srval < 0) {
		if (errno == ENOTSUP) {
			if (vflag || dflag) 
			   fsrprintf("%s: file type not supported\n", fname);
		} else if (errno == EFAULT) {
			/* The file has changed since we started the copy */
			if (vflag || dflag)
			   fsrprintf("%s:file modified defrag aborted\n", 
				     fname);
		} else if (errno == EBUSY) {
			/* Timestamp has changed or mmap'ed file */
			if (vflag || dflag)
			   fsrprintf("%s: file busy \n", fname);
		} else {
			fsrprintf("XFS_IOC_SWAPEXT failed: %s: %s\n", 
				  fname, strerror(errno));
		}
		close(tfd);
		return -1;
	}

	/* Report progress */
	if (vflag)
		fsrprintf("extents before:%d after:%d %s %s\n",
			  cur_nextents, new_nextents, 
			  (new_nextents <= nextents ? "DONE" : "    " ),
		          fname);
	close(tfd);
	return 0;
}