9fid.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "stdinc.h"
  10. #include "9.h"
  11. static struct {
  12. VtLock* lock;
  13. Fid* free;
  14. int nfree;
  15. int inuse;
  16. } fbox;
  17. static void
  18. fidLock(Fid* fid, int flags)
  19. {
  20. if(flags & FidFWlock){
  21. vtLock(fid->lock);
  22. fid->flags = flags;
  23. }
  24. else
  25. vtRLock(fid->lock);
  26. /*
  27. * Callers of file* routines are expected to lock fsys->fs->elk
  28. * before making any calls in order to make sure the epoch doesn't
  29. * change underfoot. With the exception of Tversion and Tattach,
  30. * that implies all 9P functions need to lock on entry and unlock
  31. * on exit. Fortunately, the general case is the 9P functions do
  32. * fidGet on entry and fidPut on exit, so this is a convenient place
  33. * to do the locking.
  34. * No fsys->fs->elk lock is required if the fid is being created
  35. * (Tauth, Tattach and Twalk). FidFCreate is always accompanied by
  36. * FidFWlock so the setting and testing of FidFCreate here and in
  37. * fidUnlock below is always done under fid->lock.
  38. * A side effect is that fidFree is called with the fid locked, and
  39. * must call fidUnlock only after it has disposed of any File
  40. * resources still held.
  41. */
  42. if(!(flags & FidFCreate))
  43. fsysFsRlock(fid->fsys);
  44. }
  45. static void
  46. fidUnlock(Fid* fid)
  47. {
  48. if(!(fid->flags & FidFCreate))
  49. fsysFsRUnlock(fid->fsys);
  50. if(fid->flags & FidFWlock){
  51. fid->flags = 0;
  52. vtUnlock(fid->lock);
  53. return;
  54. }
  55. vtRUnlock(fid->lock);
  56. }
  57. static Fid*
  58. fidAlloc(void)
  59. {
  60. Fid *fid;
  61. vtLock(fbox.lock);
  62. if(fbox.nfree > 0){
  63. fid = fbox.free;
  64. fbox.free = fid->hash;
  65. fbox.nfree--;
  66. }
  67. else{
  68. fid = vtMemAllocZ(sizeof(Fid));
  69. fid->lock = vtLockAlloc();
  70. fid->alock = vtLockAlloc();
  71. }
  72. fbox.inuse++;
  73. vtUnlock(fbox.lock);
  74. fid->con = nil;
  75. fid->fidno = NOFID;
  76. fid->ref = 0;
  77. fid->flags = 0;
  78. fid->open = FidOCreate;
  79. assert(fid->fsys == nil);
  80. assert(fid->file == nil);
  81. fid->qid = (Qid){0, 0, 0};
  82. assert(fid->uid == nil);
  83. assert(fid->uname == nil);
  84. assert(fid->db == nil);
  85. assert(fid->excl == nil);
  86. assert(fid->rpc == nil);
  87. assert(fid->cuname == nil);
  88. fid->hash = fid->next = fid->prev = nil;
  89. return fid;
  90. }
  91. static void
  92. fidFree(Fid* fid)
  93. {
  94. if(fid->file != nil){
  95. fileDecRef(fid->file);
  96. fid->file = nil;
  97. }
  98. if(fid->db != nil){
  99. dirBufFree(fid->db);
  100. fid->db = nil;
  101. }
  102. fidUnlock(fid);
  103. if(fid->uid != nil){
  104. vtMemFree(fid->uid);
  105. fid->uid = nil;
  106. }
  107. if(fid->uname != nil){
  108. vtMemFree(fid->uname);
  109. fid->uname = nil;
  110. }
  111. if(fid->excl != nil)
  112. exclFree(fid);
  113. if(fid->rpc != nil){
  114. close(fid->rpc->afd);
  115. auth_freerpc(fid->rpc);
  116. fid->rpc = nil;
  117. }
  118. if(fid->fsys != nil){
  119. fsysPut(fid->fsys);
  120. fid->fsys = nil;
  121. }
  122. if(fid->cuname != nil){
  123. vtMemFree(fid->cuname);
  124. fid->cuname = nil;
  125. }
  126. vtLock(fbox.lock);
  127. fbox.inuse--;
  128. if(fbox.nfree < 10){
  129. fid->hash = fbox.free;
  130. fbox.free = fid;
  131. fbox.nfree++;
  132. }
  133. else{
  134. vtLockFree(fid->alock);
  135. vtLockFree(fid->lock);
  136. vtMemFree(fid);
  137. }
  138. vtUnlock(fbox.lock);
  139. }
  140. static void
  141. fidUnHash(Fid* fid)
  142. {
  143. Fid *fp, **hash;
  144. assert(fid->ref == 0);
  145. hash = &fid->con->fidhash[fid->fidno % NFidHash];
  146. for(fp = *hash; fp != nil; fp = fp->hash){
  147. if(fp == fid){
  148. *hash = fp->hash;
  149. break;
  150. }
  151. hash = &fp->hash;
  152. }
  153. assert(fp == fid);
  154. if(fid->prev != nil)
  155. fid->prev->next = fid->next;
  156. else
  157. fid->con->fhead = fid->next;
  158. if(fid->next != nil)
  159. fid->next->prev = fid->prev;
  160. else
  161. fid->con->ftail = fid->prev;
  162. fid->prev = fid->next = nil;
  163. fid->con->nfid--;
  164. }
  165. Fid*
  166. fidGet(Con* con, uint32_t fidno, int flags)
  167. {
  168. Fid *fid, **hash;
  169. if(fidno == NOFID)
  170. return nil;
  171. hash = &con->fidhash[fidno % NFidHash];
  172. vtLock(con->fidlock);
  173. for(fid = *hash; fid != nil; fid = fid->hash){
  174. if(fid->fidno != fidno)
  175. continue;
  176. /*
  177. * Already in use is an error
  178. * when called from attach, clone or walk.
  179. */
  180. if(flags & FidFCreate){
  181. vtUnlock(con->fidlock);
  182. vtSetError("%s: fid 0x%ud in use", argv0, fidno);
  183. return nil;
  184. }
  185. fid->ref++;
  186. vtUnlock(con->fidlock);
  187. fidLock(fid, flags);
  188. if((fid->open & FidOCreate) || fid->fidno == NOFID){
  189. fidPut(fid);
  190. vtSetError("%s: fid invalid", argv0);
  191. return nil;
  192. }
  193. return fid;
  194. }
  195. if((flags & FidFCreate) && (fid = fidAlloc()) != nil){
  196. assert(flags & FidFWlock);
  197. fid->con = con;
  198. fid->fidno = fidno;
  199. fid->ref = 1;
  200. fid->hash = *hash;
  201. *hash = fid;
  202. if(con->ftail != nil){
  203. fid->prev = con->ftail;
  204. con->ftail->next = fid;
  205. }
  206. else{
  207. con->fhead = fid;
  208. fid->prev = nil;
  209. }
  210. con->ftail = fid;
  211. fid->next = nil;
  212. con->nfid++;
  213. vtUnlock(con->fidlock);
  214. /*
  215. * The FidOCreate flag is used to prevent any
  216. * accidental access to the Fid between unlocking the
  217. * hash and acquiring the Fid lock for return.
  218. */
  219. fidLock(fid, flags);
  220. fid->open &= ~FidOCreate;
  221. return fid;
  222. }
  223. vtUnlock(con->fidlock);
  224. vtSetError("%s: fid not found", argv0);
  225. return nil;
  226. }
  227. void
  228. fidPut(Fid* fid)
  229. {
  230. vtLock(fid->con->fidlock);
  231. assert(fid->ref > 0);
  232. fid->ref--;
  233. vtUnlock(fid->con->fidlock);
  234. if(fid->ref == 0 && fid->fidno == NOFID){
  235. fidFree(fid);
  236. return;
  237. }
  238. fidUnlock(fid);
  239. }
  240. void
  241. fidClunk(Fid* fid)
  242. {
  243. assert(fid->flags & FidFWlock);
  244. vtLock(fid->con->fidlock);
  245. assert(fid->ref > 0);
  246. fid->ref--;
  247. fidUnHash(fid);
  248. fid->fidno = NOFID;
  249. vtUnlock(fid->con->fidlock);
  250. if(fid->ref > 0){
  251. /* not reached - fidUnHash requires ref == 0 */
  252. fidUnlock(fid);
  253. return;
  254. }
  255. fidFree(fid);
  256. }
  257. void
  258. fidClunkAll(Con* con)
  259. {
  260. Fid *fid;
  261. uint32_t fidno;
  262. vtLock(con->fidlock);
  263. while(con->fhead != nil){
  264. fidno = con->fhead->fidno;
  265. vtUnlock(con->fidlock);
  266. if((fid = fidGet(con, fidno, FidFWlock)) != nil)
  267. fidClunk(fid);
  268. vtLock(con->fidlock);
  269. }
  270. vtUnlock(con->fidlock);
  271. }
  272. void
  273. fidInit(void)
  274. {
  275. fbox.lock = vtLockAlloc();
  276. }