package org.dcache.chimera.nfsv41.mover; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import org.dcache.nfs.ChimeraNFSException; import org.dcache.nfs.nfsstat; import org.dcache.nfs.status.BadStateidException; import org.dcache.nfs.status.PermException; import org.dcache.nfs.v4.AbstractNFSv4Operation; import org.dcache.nfs.v4.CompoundContext; import org.dcache.nfs.v4.xdr.WRITE4res; import org.dcache.nfs.v4.xdr.WRITE4resok; import org.dcache.nfs.v4.xdr.count4; import org.dcache.nfs.v4.xdr.nfs_argop4; import org.dcache.nfs.v4.xdr.nfs_opnum4; import org.dcache.nfs.v4.xdr.nfs_resop4; import org.dcache.nfs.v4.xdr.stable_how4; import org.dcache.pool.movers.IoMode; import org.dcache.pool.repository.OutOfDiskException; import org.dcache.pool.repository.RepositoryChannel; public class EDSOperationWRITE extends AbstractNFSv4Operation { private static final Logger _log = LoggerFactory.getLogger(EDSOperationWRITE.class.getName()); private final NFSv4MoverHandler _moverHandler; public EDSOperationWRITE(nfs_argop4 args, NFSv4MoverHandler moverHandler) { super(args, nfs_opnum4.OP_WRITE); _moverHandler = moverHandler; } @Override public void process(CompoundContext context, nfs_resop4 result) { final WRITE4res res = result.opwrite; try { NfsMover mover = _moverHandler.getOrCreateMover(context.getRemoteSocketAddress(), _args.opwrite.stateid, context.currentInode().toNfsHandle()); if (mover == null) { throw new BadStateidException("No mover associated with given stateid: " + _args.opwrite.stateid); } mover.attachSession(context.getSession()); if( mover.getIoMode() != IoMode.WRITE ) { throw new PermException("an attempt to write without IO mode enabled"); } long offset = _args.opwrite.offset.value; RepositoryChannel fc = mover.getMoverChannel(); _args.opwrite.data.rewind(); int bytesWritten = fc.write(_args.opwrite.data, offset); /* due to bug in linux commit-through-ds code, we shamelessly always return FILE_SYNC4 without committing. RedHat Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1184394 */ int stable = stable_how4.FILE_SYNC4; /* FIXME: enable this back as soon as kernel bug is fixed int stable = _args.opwrite.stable; switch (stable) { case stable_how4.FILE_SYNC4: mover.commitFileSize(fc.size()); // FILE_SYNC includes DATA_SYNC case stable_how4.DATA_SYNC4: fc.sync(); break; case stable_how4.UNSTABLE4: // nop break; default: throw new BadXdrException(); } */ res.status = nfsstat.NFS_OK; res.resok4 = new WRITE4resok(); res.resok4.count = new count4(bytesWritten); res.resok4.committed = stable; res.resok4.writeverf = mover.getBootVerifier(); _log.debug("MOVER: {}@{} written, {} requested.", bytesWritten, offset, bytesWritten); }catch(ChimeraNFSException he) { _log.debug(he.getMessage()); res.status = he.getStatus(); }catch (OutOfDiskException e) { _log.error("DSWRITE: no allocatable space left on the pool"); res.status = nfsstat.NFSERR_NOSPC; }catch(IOException ioe) { _log.error("DSWRITE: ", ioe); res.status = nfsstat.NFSERR_IO; }catch(Exception e) { _log.error("DSWRITE: ", e); res.status = nfsstat.NFSERR_SERVERFAULT; } } }