Sorry for the delay in review, I'll admit it's at least partly because the existing code structure is not the easiest to follow...
In general, Windows file system drivers process pathnames on its own (for IRP_MJ_CREATE), since putting every existing file into the in-memory namespace is slow and highly inefficient.
Well... sort of?
Putting every *opened* file in the in-memory namespace is necessary no matter what.
Putting every *openable* file path in the in-memory namespace isn't actually necessary. You can create files from lookup_name(). The only problem is that I think this is architecturally ugly (although perhaps that's just because lookup_name() is called what it is). But there's precedent for it, namely console_device_lookup_name(). I explicitly argued against doing this earlier, probably because I didn't realize we had precedent for it.
We could also implement this within the existing architecture and also avoid creating objects from lookup_name. In order to do this you'd need to create a separate object (when the named pipe device is created, presumably), which isn't exactly a file *or* a device but is rather analogous to struct named_pipe, so it would have an open_file which would probably return a named_pipe_device_file; a link_name (unless we just bypass that), and named_pipe_device_lookup_name() would return it if and only if there was a trailing backslash.
I'm inclined to believe this patch series is better, although it does some arguably unnecessary refactoring. It avoids creating a new object type, avoids the conceptual weirdness of creating objects from lookup_name(), and I think it moves towards making the object lookup simpler and more intuitive.