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 }
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 }
/* * 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; }