As we mentioned in Section 5, the fusd_file_info structure has two seemingly similar fields, both of which can be used by drivers to store their own data: device_info and private_data. However, there is an important difference between them:
The first time a FUSD driver sees private_data (in the open callback), it is guaranteed to be NULL. Any changes to it by a driver callback will only affect the state associated with that single file descriptor.
In short, device_info is used to differentiate devices. private_data is used to differentiate users of those devices.
Program 5, drums2.c, illustrates the difference between device_info and private_data. Like the original drums.c, it creates a bunch of devices in /dev/drums/, each of which ``plays'' a different sound. However, it also does something new: keeps track of how many times each device has been opened. Every read to any drum gives you the name of its sound as well as your unique ``user number''. And, instead of returning just a single line (as drums.c did), it will keep generating more ``sound'' every time a read() system call arrives.
The trick is that we want to keep users separate from each other. For
example, user one might type:
% more /dev/drums/bam You are user 1 to hear a drum go 'bam'! You are user 1 to hear a drum go 'bam'! You are user 1 to hear a drum go 'bam'! ...
Meanwhile, another user in a different shell might type the same
command at the same time, and get different results:
% more /dev/drums/bam You are user 2 to hear a drum go 'bam'! You are user 2 to hear a drum go 'bam'! You are user 2 to hear a drum go 'bam'! ...
The idea is that no matter how long those two users go on reading their devices, the driver always generates a message that is specific to that user. The two users' data are not intermingled.
To implement this, Program 5 introduces a new drum_info structure (lines 1-4), which keeps track of both the drum's name, and the number of time each drum device has been opened. An instance of this structure, drums, is initialized on lines 4-8. Note that the call to fusd_register (line 45) now passes a pointer to a drum_info structure. (This drum_info * pointer is shared by every instance of a client that opens a particular type of drum.)
Each time a drum device is opened, its drum_info structure is retrieved from device_info (line 15). Then, on line 18, the num_users field is incremented and the new user number is stored in fusd_file_info's private_data field. To reiterate our earlier point: device_info contains information global to all users of a device, while private_data has information specific to a particular user of the device.
It's also worthwhile to note that when we increment num_users on line 18, a simple num_users++ is correct. If this was a driver inside the kernel, we'd have to use something like atomic_inc() because a plain i++ is not atomic. Such a non-atomic statement will result in a race condition on SMP platforms, if an interrupt handler also touches num_users, or in some future Linux kernel that is preemptive. Since this FUSD driver is just a plain, single-threaded user-space application, good old ++ still works.