use of org.dcache.nfs.status.StaleException in project dcache by dCache.
the class ChimeraVfs method setattr.
@Override
public void setattr(Inode inode, Stat stat) throws IOException {
FsInode fsInode = toFsInode(inode);
try {
if (shouldRejectAttributeUpdates(fsInode, _fs)) {
throw new PermException("setStat not allowed.");
}
// OperationSETATTR have already checked for a valid open stateid
if (stat.isDefined(Stat.StatAttribute.SIZE)) {
var chimeraStat = fsInode.stat();
int type = chimeraStat.getMode() & UnixPermission.F_TYPE;
switch(type) {
case UnixPermission.S_IFREG:
// ok
break;
case UnixPermission.S_IFDIR:
throw new IsDirException("Can't update size of a directory");
default:
throw new InvalException("Can't update size of a non file object");
}
// allow set size only for newly created files
if (fsInode.type() == FsInodeType.INODE && chimeraStat.getState() != FileState.CREATED) {
throw new PermException("Can't change size of existing file");
}
}
org.dcache.chimera.posix.Stat chimeraStat = toChimeraStat(stat);
// convert empty setattr to noop
if (!chimeraStat.getDefinedAttributeses().isEmpty()) {
fsInode.setStat(chimeraStat);
}
} catch (InvalidArgumentChimeraException e) {
throw new InvalException(e.getMessage());
} catch (IsDirChimeraException e) {
throw new IsDirException(e.getMessage());
} catch (FileNotFoundChimeraFsException e) {
throw new StaleException(e.getMessage());
} catch (PermissionDeniedChimeraFsException e) {
throw new PermException(e.getMessage());
}
}
use of org.dcache.nfs.status.StaleException in project dcache by dCache.
the class ChimeraVfs method setAcl.
@Override
public void setAcl(Inode inode, nfsace4[] acl) throws IOException {
FsInode fsInode = toFsInode(inode);
List<ACE> dacl = new ArrayList<>();
for (nfsace4 ace : acl) {
dacl.add(valueOf(ace, _idMapping));
}
try {
_fs.setACL(fsInode, dacl);
} catch (FileNotFoundChimeraFsException e) {
throw new StaleException(e.getMessage());
}
}
use of org.dcache.nfs.status.StaleException in project dcache by dCache.
the class NFSv41Door method layoutGet.
/**
* ask pool manager for a file
* <p>
* On successful reply from pool manager corresponding O request will be sent to the pool to
* start a NFS mover.
*
* @throws ChimeraNFSException in case of NFS friendly errors ( like ACCESS )
* @throws IOException in case of any other errors
*/
@Override
public Layout layoutGet(CompoundContext context, LAYOUTGET4args args) throws IOException {
Inode nfsInode = context.currentInode();
layouttype4 layoutType = layouttype4.valueOf(args.loga_layout_type);
final stateid4 stateid = Stateids.getCurrentStateidIfNeeded(context, args.loga_stateid);
LayoutDriver layoutDriver = getLayoutDriver(layoutType);
final NFS4Client client;
if (context.getMinorversion() == 0) {
/* if we need to run proxy-io with NFSv4.0 */
client = context.getStateHandler().getClientIdByStateId(stateid);
} else {
client = context.getSession().getClient();
}
CDC cdcContext = CDC.reset(getCellName(), getCellDomainName());
try {
FsInode inode = _chimeraVfs.inodeFromBytes(nfsInode.getFileId());
PnfsId pnfsId = new PnfsId(inode.getId());
deviceid4[] devices;
final NFS4State openStateId = client.state(stateid).getOpenState();
final NFS4State layoutStateId;
// serialize all requests by the same stateid
synchronized (openStateId) {
if (inode.type() != FsInodeType.INODE || inode.getLevel() != 0) {
/*
* all non regular files ( AKA pnfs dot files ) provided by door itself.
*/
throw new LayoutUnavailableException("special DOT file");
}
final InetSocketAddress remote = context.getRpcCall().getTransport().getRemoteSocketAddress();
final NFS4ProtocolInfo protocolInfo = new NFS4ProtocolInfo(remote, new org.dcache.chimera.nfs.v4.xdr.stateid4(stateid), nfsInode.toNfsHandle());
NfsTransfer transfer = _transfers.get(openStateId.stateid());
if (transfer == null) {
Transfer.initSession(false, false);
NDC.push(pnfsId.toString());
NDC.push(context.getRpcCall().getTransport().getRemoteSocketAddress().toString());
transfer = args.loga_iomode == layoutiomode4.LAYOUTIOMODE4_RW ? new WriteTransfer(_pnfsHandler, client, openStateId, nfsInode, context.getRpcCall().getCredential().getSubject()) : new ReadTransfer(_pnfsHandler, client, openStateId, nfsInode, context.getRpcCall().getCredential().getSubject());
transfer.setProtocolInfo(protocolInfo);
transfer.setCellAddress(getCellAddress());
transfer.setBillingStub(_billingStub);
transfer.setPoolStub(_poolStub);
transfer.setPoolManagerStub(_poolManagerStub);
transfer.setPnfsId(pnfsId);
transfer.setClientAddress(remote);
transfer.setIoQueue(_ioQueue);
transfer.setKafkaSender(_kafkaSender);
/*
* As all our layouts marked 'return-on-close', stop mover when
* open-state disposed on CLOSE.
*/
final NfsTransfer t = transfer;
openStateId.addDisposeListener(state -> {
/*
* Cleanup transfer when state invalidated.
*/
if (t.hasMover()) {
// to work correctly with proxy-io. As modern rhel clients (>= 7) use flex_files by default it's ok.
if (layoutType == layouttype4.LAYOUT4_FLEX_FILES && client.isLeaseValid() && client.getCB() != null) {
/*
* Due to race in the Linux kernel client, a server might see CLOSE before
* the last WRITE operation have been processed by a data server. Thus,
* recall the layout (enforce dirty page flushing) and return a NFS4ERR_DELAY.
*
* see: https://bugzilla.redhat.com/show_bug.cgi?id=1901524
*/
_log.warn("Deploying work-around for buggy client {} issuing CLOSE before LAYOUT_RETURN for transfer {}@{} of {}", t.getMoverId(), t.getPool(), t.getPnfsId(), t.getClient().getRemoteAddress());
t.recallLayout(_callbackExecutor);
throw new DelayException("Close before layoutreturn");
} else {
_log.warn("Removing orphan mover: {}@{} for {} by {}", t.getMoverId(), t.getPool(), t.getPnfsId(), t.getClient().getRemoteAddress());
t.shutdownMover();
}
}
if (t.isWrite()) {
/* write request keep in the message map to
* avoid re-creates and trigger errors.
*/
_transfers.remove(openStateId.stateid());
}
});
_transfers.put(openStateId.stateid(), transfer);
} else {
// keep debug context in sync
transfer.restoreSession();
NDC.push(pnfsId.toString());
NDC.push(context.getRpcCall().getTransport().getRemoteSocketAddress().toString());
}
layoutStateId = transfer.getStateid();
devices = transfer.getPoolDataServers(NFS_REQUEST_BLOCKING);
}
// -1 is special value, which means entire file
layout4 layout = new layout4();
layout.lo_iomode = args.loga_iomode;
layout.lo_offset = new offset4(0);
layout.lo_length = new length4(nfs4_prot.NFS4_UINT64_MAX);
layout.lo_content = layoutDriver.getLayoutContent(stateid, NFSv4Defaults.NFS4_STRIPE_SIZE, new nfs_fh4(nfsInode.toNfsHandle()), devices);
layoutStateId.bumpSeqid();
if (args.loga_iomode == layoutiomode4.LAYOUTIOMODE4_RW) {
// in case of WRITE, invalidate vfs cache on close
layoutStateId.addDisposeListener(state -> _vfsCache.invalidateStatCache(nfsInode));
}
return new Layout(true, layoutStateId.stateid(), new layout4[] { layout });
} catch (FileNotFoundCacheException e) {
/*
* The file is removed before we was able to start a mover.
* Invalidate state as client will not send CLOSE for a stale file
* handle.
*
* NOTICE: according POSIX, the opened file must be still accessible
* after remove as long as it not closed. We violate that requirement
* in favor of dCache shared state simplicity.
*/
client.releaseState(stateid);
throw new StaleException("File is removed", e);
} catch (CacheException | ChimeraFsException | TimeoutException | ExecutionException e) {
throw asNfsException(e, LayoutTryLaterException.class);
} catch (InterruptedException e) {
throw new LayoutTryLaterException(e.getMessage(), e);
} finally {
cdcContext.close();
}
}
use of org.dcache.nfs.status.StaleException in project dcache by dCache.
the class ChimeraVfs method getAcl.
@Override
public nfsace4[] getAcl(Inode inode) throws IOException {
FsInode fsInode = toFsInode(inode);
try {
nfsace4[] aces;
List<ACE> dacl = _fs.getACL(fsInode);
org.dcache.chimera.posix.Stat stat = fsInode.statCache();
nfsace4[] unixAcl = Acls.of(stat.getMode(), fsInode.isDirectory());
aces = new nfsace4[dacl.size() + unixAcl.length];
int i = 0;
for (ACE ace : dacl) {
aces[i] = valueOf(ace, _idMapping);
i++;
}
System.arraycopy(unixAcl, 0, aces, i, unixAcl.length);
return Acls.compact(aces);
} catch (FileNotFoundChimeraFsException e) {
throw new StaleException(e.getMessage());
}
}
Aggregations