nn.DataParallel will split the input batch in dim0 and send each chunk in the shize [batch_size//nb_gpus] to each specified device.
Each device will get a model replica, which will synchronize the parameters and buffers, but not the tensors. The self.foo tensor will thus only be updated in the replica temporarily and not reduced to the original model.
Assuming you are using 2 GPUs the output corresponds to:
A: torch.Size([1]) # m.module(torch.ones(1, 4, 6, 6).cuda())

# DataParallel call with bs=2
A: torch.Size([1]) # device0
A: torch.Size([1]) # device1
B: torch.Size([1]) # original model

# DataParallel call with bs=3
A: torch.Size([2]) # device0
A: torch.Size([1]) # device1
B: torch.Size([1]) # original model

# DataParallel call with bs=4
A: torch.Size([2]) # device0
A: torch.Size([2]) # device1
B: torch.Size([1]) # original model