In "net/unix/af_unix.c: Set ATIME on socket inode" (back in 2002) we'd grown something rather odd in unix_find_other(). In the original patch it was u=unix_find_socket_byname(sunname, len, type, hash); - if (!u) + if (u) { + struct dentry *dentry; + dentry = u->protinfo.af_unix.dentry; + if (dentry) + UPDATE_ATIME(dentry->d_inode); + } else goto fail;
These days the code is u = unix_find_socket_byname(net, sunname, len, type, hash); if (u) { struct dentry *dentry; dentry = unix_sk(u)->path.dentry; if (dentry) touch_atime(&unix_sk(u)->path); } else goto fail; but the logics is the same. It's the abstract address case - we have '\0' in sunname->sun_path[0]. How in hell could that possibly have non-NULL ->path.dentry and what would it be? Note that unix_find_socket_byname() returns non-NULL u here only if u->addr->name->sun_path[0] is equal to sunname->sun_path[0], i.e. '\0'. There are only two places where we ever might assign non-NULL to ->path.dentry: if (sun_path[0]) { addr->hash = UNIX_HASH_SIZE; hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1); spin_lock(&unix_table_lock); u->path = path; list = &unix_socket_table[hash]; } else { in unix_bind() (in which case u->addr->name->sun_path[0] will not be '\0') and /* copy address information from listening to new sock*/ if (otheru->addr) { refcount_inc(&otheru->addr->refcnt); newu->addr = otheru->addr; } if (otheru->path.dentry) { path_get(&otheru->path); newu->path = otheru->path; } in unix_stream_connect(). And once ->addr is non-NULL, it's never changed, and ->addr->name contents is never modified afterwards. So we would have to had the same condition (non-NULL ->path.dentry with '\0' in ->addr->name->sun_path[0]) at earlier point on the listener socket. Looks like that should be impossible; what am I missing here? Incidentally, how can the quoted fragment in in unix_stream_connect() be reached with NULL otheru->addr? After all, otheru is unix_sock of a listener; how could we possibly have found it if it had NULL ->addr? Confused...